Normal behavior: flagOutcome may be re-flagged by the moderator at any time before the first claim (claimsStarted == false), specifically so a mistaken outcome or attacker address can be corrected before any participant locks in a wrong distribution (docs/DESIGN.md §4). For a good-faith CORRUPTED correction, bountyEntitlement is re-snapshotted as snapshotTotalStaked + snapshotTotalBonus the named attacker is meant to receive the entire pool, staked principal plus bonus (docs/DESIGN.md §12).
The specific issue: sweepUnclaimedBonus is callable by anyone whenever outcome == SURVIVED (or EXPIRED), with no check on claimsStarted this is intentional, so a 1-wei donation can't be used to grief the moderator's re-flag window. When riskWindowStart == 0 (which the contract's own §5 "no-risk-window CORRUPTED race" documents as a reachable state even on a pool that is ultimately CORRUPTED), the function reserves none of totalBonus and sweeps the entire bonus to recoveryAddress, also decrementing the live totalBonus state variable. If the moderator's first flag was a mistaken SURVIVED (e.g. an out-of-scope judgement call that later needs correcting), anyone can sweep the whole bonus away in the gap before the moderator re-flags to good-faith CORRUPTED. The subsequent correction re-snapshots snapshotTotalBonus from the now-drained totalBonus, so the correctly-named attacker's "entire pool" entitlement is short by however much was swept — permanently, since the sweep already left the contract.
Likelihood:
Occurs whenever the moderator's first flagOutcome call names an outcome other than the correct one and the registry-observed risk window never opened locally (riskWindowStart == 0) a state the contract's own documentation (§5) treats as a normal, reachable outcome for a pool that is later confirmed CORRUPTED, not a contrived edge case.
sweepUnclaimedBonus is a permissionless, no-incentive-required "keeper" function by design, any bot, MEV searcher, or even an unrelated party sweeping dust will trigger it the moment SURVIVED is flagged and riskWindowStart == 0, well before the moderator has a chance to review and correct the outcome.
Impact:
The good-faith CORRUPTED attacker, the party the protocol is specifically trying to reward for responsible disclosure, receives less than the documented "entire pool" entitlement, with no way to recover the swept difference; claimAttackerBounty pays min(remaining, freeBalance), and the shortfall is already at recoveryAddress.
Silently breaks the accounting invariant stated in docs/DESIGN.md §12 ("the entire pool is the named attacker's bounty") without reverting or emitting any signal that the entitlement was short-changed.
Withhold the bonus reservation until either the risk window was genuinely observed, or the re-flag correction window has actually closed (i.e. a claim has occurred) — regardless of whether stakers currently remain, since a good-faith CORRUPTED correction can still name an attacker entitled to the bonus even with zero remaining stakers:
This keeps the bonus sweepable for genuinely resolved, uncontested outcomes (once any participant has claimed, the re-flag window is already closed by docs/DESIGN.md §4's own finality rule) while closing the window in which a premature sweep can undercut a pending correction.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.