# Challenger misses discrepancy events, allowing executors to perform malicious actions

Challenger bot's endBlockHandler overwrites the challenges variable with timeout challenges, discarding discrepancy events so malicious Executor proposals go unchallenged.

- Payout: Contest reward
- Severity: high
- Program: Initia
- Credited: 0xAlix2
- Disclosed: 2025-04-10
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2025-01-initia-rollup-modules#h-01
- Library page: https://bugbountylibrary.com/r/c4%3A2025-01-initia-rollup-modules%3AH-01
- Tags: domain:web3 impact:integrity kind:contest platform:code4rena sev:high tech:go technique:source-review vuln:access-control vuln:business-logic

**Target:** opinit-bots Challenger child endBlockHandler (Go)
**Root cause:** In endBlockHandler, `challenges` from CheckValue (discrepancy detection) is reassigned by CheckTimeout's return, and only `challenges` is passed to SendPendingChallenges instead of the accumulated `pendingChallenges`, dropping discrepancy events.
**Steps:**
1. Read challenger/child/handler.go endBlockHandler.
2. Observe `challenges, processedEvents := CheckValue(...)` then `challenges, timeoutEvents := CheckTimeout(...)` overwrites the variable.
3. Note `pendingChallenges` accumulates both but `SendPendingChallenges(challenges)` sends only timeout challenges.
4. Conclude discrepancy events never reach challengeHandler goroutine.
**How found:** Code review of the Challenger's event-handling flow, noticing the variable shadowing/reassignment between CheckValue and CheckTimeout and the wrong variable passed to SendPendingChallenges.
**Exploitation:** A malicious Executor submits an invalid output proposal (e.g., mismatched FinalizeTokenDeposit vs InitiateTokenDeposit). The Challenger detects the discrepancy in CheckValue but discards it, so no challenge is issued and the invalid rollup state is accepted.
**Insight:** In event-accumulation handlers, trace which variable is actually forwarded to the sink; a reassignment between two check functions silently drops the first result set even when both are appended to an accumulator.
