Normal behavior: when a pool resolves SURVIVED/EXPIRED with riskWindowStart == 0 ("no observed risk"; the registry skipped the active-risk states entirely), _bonusShare owes the bonus to no staker, so sweepUnclaimedBonus() is permissionlessly allowed to recover the unowed bonus to recoveryAddress. Separately, because flagOutcome only closes its re-flag window once claimsStarted is true, and sweepUnclaimedBonus() deliberately does not set claimsStarted, a moderator can still re-flag the pool as good-faith CORRUPTED afterward if the agreement is genuinely breached later, naming the real whitehat attacker and re-snapshotting their bountyEntitlement off the live totalBonus/totalEligibleStake.
The problem: sweepUnclaimedBonus() physically transfers the bonus out and zeroes totalBonus when it decides the bonus is currently unowed, but it does this irreversibly, even though it intentionally keeps the re-flag window open for exactly the scenario where that bonus becomes owed to someone else moments later. When the moderator subsequently re-flags good-faith CORRUPTED, flagOutcome re-snapshots snapshotTotalBonus = totalBonus, which is now 0. The named whitehat's bountyEntitlement silently excludes the bonus, which is unrecoverably sitting at recoveryAddress instead of following the attacker's bounty as the CORRUPTED/good-faith payout rule intends.
Likelihood:
Occurs whenever a pool resolves SURVIVED/EXPIRED with riskWindowStart == 0 (registry transitioned straight from pre-attack staging to a terminal state, e.g. NEW_DEPLOYMENT PRODUCTION) a state the protocol's own docs treat as a normal, expected edge case, not a rare fault.
sweepUnclaimedBonus() is permissionless and requires no staker action first, so any observer (a bot, a competing sponsor, or recoveryAddress's own owner) will sweep the bonus as soon as it becomes sweepable, well before the pool's underlying agreement's real fate is known.
The re-flag path is a documented, intended moderator workflow (correcting an outcome, naming a whitehat after the fact when a real attack surfaces post-"resolution"); it is not a contrived edge case; it is the exact mechanism sweepUnclaimedBonus was written to stay compatible with.
Impact:
The bonus (the sponsor-funded incentive specifically meant to reward whoever ends up entitled to it under a CORRUPTED outcome) settles at recoveryAddress controlled by the sponsor/pool owner instead of the whitehat attacker the moderator names in good faith.
Breaks the documented CORRUPTED/good-faith payout guarantee that the full pool (stake + bonus) is owed to the named attacker, silently reducing it to stake-only with no on-chain signal that anything went wrong (the transaction succeeds, bountyEntitlement is simply smaller than expected).
Add this file to the mock folder
Add this POC to the unit test folder.
This closes the re-flag window as soon as real value moves, matching every other claim entrypoint. If a 1-wei donation griefing a moderator's re-flag is a concern worth preserving against, prefer gating sweepUnclaimedBonus() behind a minimum post-resolution delay (mirroring MODERATOR_CORRUPTED_GRACE) long enough for a moderator to act on a freshly observed CORRUPTED state first, rather than leaving the sweep able to permanently strip funds out from under a still-open re-flag window.
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.