The protocol lets the moderator correct a pool's outcome by re-flagging, and keeps that correction window open until claimsStarted is set (DESIGN.md #4 describes this window as closing once value has left the contract). Until then, flagOutcome can be called again.
sweepUnclaimedBonus transfers the bonus out of the pool to recoveryAddress but does not set claimsStarted. So value can leave the contract while the re-flag window is still open. The exploit and control paths differ only by the interleaved sweepUnclaimedBonus() call.
If the moderator subsequently re-flags the pool as good-faith CORRUPTED, bountyEntitlement is recomputed from snapshotTotalBonus, which the sweep has already reduced to zero. The attacker's entitlement is therefore P instead of P + B, and B remains at recoveryAddress.
Likelihood:
The pool is initially flagged SURVIVED and is subsequently re-flagged good-faith CORRUPTED before claimsStarted becomes true, using the documented pre-claim correction mechanism (#4)
Impact:
The good-faith attacker's entitlement is reduced from P + B to P because B has already been transferred to recoveryAddress.
Triggerable by any unprivileged caller, the loss falls on the attacker, who is not yet a party to the pool when the value moves.
run the test by the command forge test --match-path 'test/poc/SweepReflagBonusRedirection.t.sol' -vvvv
The violated invariant is that a re-flag must never recompute settlement (bountyEntitlement and the snapshots feeding it) from accounting that has already been economically finalized by an earlier value-moving operation.
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.