The protocol defines exactly three terminal outcomes, each with a fully specified settlement: SURVIVED/EXPIRED return funds to stakers (or, with no observed risk window, route the bonus to recoveryAddress under a stable SURVIVED), and good-faith CORRUPTED sends the whole pool — principal and bonus — to the named attacker. The moderator may re-flag the outcome pre-claim to correct a scope judgement, which is a documented, supported path.
While the outcome transiently reads SURVIVED but is not yet stable, the permissionless sweepUnclaimedBonus() irreversibly transfers the bonus to recoveryAddress. When the moderator then corrects the outcome to good-faith CORRUPTED, the funds are already gone, and the pool settles into outcome = CORRUPTED, bounty -> attacker, bonus -> recoveryAddress — a distribution no defined outcome produces. The final attacker bounty therefore depends on whether the sweep executed before the corrective re-flag, not solely on the final outcome.
Likelihood:
When the registry reaches a terminal state without the pool observing the active-risk window (riskWindowStart == 0), the full bonus is unreserved and sweepable in a single call.
When the moderator flags SURVIVED and then corrects to good-faith CORRUPTED — the out-of-scope -> in-scope judgement revision the pre-claim re-flag window exists to support — a transient SURVIVED window is opened.
When any unprivileged account calls sweepUnclaimedBonus() during that transient window (the pending correction is mempool-observable), the bonus leaves permanently before the correction lands; the moderator cannot prevent the front-run of their own correction.
Impact:
The good-faith attacker (white-hat) is permanently denied the entire bonus portion of the bounty the corrected outcome awards them (PoC: 100e18 instead of 600e18). No theft occurs — the funds go to recoveryAddress (trusted) — so this is a misallocation of a prescribed payment, which bounds the severity to Low.
The pool settles into a final distribution — CORRUPTED outcome with the bonus at recoveryAddress — that matches none of the protocol's three defined outcomes.
The final settlement depends on transaction ordering rather than solely on the final outcome. DESIGN.md §4 keys resolution finality on value movement ("once value has left the contract, a corrective re-flag cannot be honored without breaking balance accounting"); the sweep is value leaving, yet the corrective re-flag is honored and accounting breaks — though the same section also calls a claim "the distribution-locking event," so the specification is internally ambiguous on whether this is prohibited.
Paste into a new file test/OrderDependencePoC.t.sol and run forge test --match-test test_orderDependenceOfReflagAndSweep -vv. Same initial state, same final outcome — only the ordering differs; both assertions pass:
Prevent an irreversible bonus movement while the outcome remains subject to correction. The branch that moves the bonus itself (not donation excess) is the one that must not race a re-flag, so finalize when it fires:
Alternatively, on a corrective re-flag to good-faith CORRUPTED, derive bountyEntitlement from the pool's actual balance so the final distribution always matches the final outcome regardless of any prior operation. Either approach removes the ordering dependence.
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.