DESIGN.md §4 allows the moderator to re-flag a pool's outcome pre-claim to correct a typo'd flag (e.g. SURVIVED → CORRUPTED). DESIGN.md §12 promises the named whitehat "the entire pool is the named attacker's bounty" — bountyEntitlement = snapshotTotalStaked + snapshotTotalBonus.
When riskWindowStart == 0 (no pool interaction observed the registry during active-risk states), sweepUnclaimedBonus treats the entire snapshotTotalBonus as unowed by stakers and sweeps it to recoveryAddress (DESIGN.md §5: "no observable risk → bonus sweeps to recoveryAddress"). The sweep does not set claimsStarted (lines 503-505), so the moderator's re-flag window stays open. A subsequent re-flag to good-faith CORRUPTED re-snapshots snapshotTotalBonus from the now-depleted live totalBonus = 0 (line 358), setting bountyEntitlement = snapshotTotalStaked + 0. The whitehat receives only principal; the bonus is permanently gone to the sponsor's recoveryAddress.
Likelihood:
The sponsor (who controls recoveryAddress) has direct economic incentive to preserve riskWindowStart == 0: calling pokeRiskWindow() or any pool function during active-risk states would seal the window and forfeit the sweep path. No protocol-level keeper automatically calls it.
Whitehats audit the agreement's in-scope contracts, not the ConfidencePool clone. They have no reason to interact with the pool before being named attacker — and they can't know they'll be named until after the moderator validates their disclosure and flags CORRUPTED.
Stakers' default mode is passive: they deposit pre-attack and wait for resolution. No pool interaction is required during the active-risk interval, so "no staker poked for the entire UNDER_ATTACK period" is a plausible operating condition, not a pathological edge.
The moderator correction path is explicitly sanctioned by DESIGN.md §4 ("re-flag pre-claim so the moderator can fix a typo'd outcome"). A normal operational flow — moderator optimistically flags SURVIVED before a whitehat disclosure arrives, then corrects to CORRUPTED — is not a malicious moderator, just timing.
Impact:
The whitehat attacker's bounty is reduced from snapshotTotalStaked + snapshotTotalBonus to snapshotTotalStaked only, permanently losing the bonus pool to the sponsor's recoveryAddress. This violates the DESIGN.md §12 bounty promise: "the entire pool is the named attacker's bounty".
The sponsor captures the swept bonus directly via recoveryAddress, which they can redirect at any time via setRecoveryAddress (no state gate). This creates a direct economic incentive for the sponsor to preserve riskWindowStart == 0 and front-run the moderator's correction.
Run: forge test --match-test testM01BonusSweptBeforeCorruptedReflag -vvv
Always reserving snapshotTotalBonus for live stakers ensures the bonus cannot be swept before the re-flag window closes (it only opens when stakers exist). Donations/dust above the reserve remain sweepable. After claimsStarted (first genuine claim), the re-flag window closes and residual bonus becomes sweepable normally. No new DoS, reentrancy, or invariant violations — the sweep still works for donations above the reserve.
Impact – Medium Up to the entire bonus pool can be routed to the wrong party for good, with no on-chain way to unwind it, and in a stakerless pool the effect is total since bountyEntitlement computes to zero and claimAttackerBounty reverts outright. This impact is definitely not High: the pool stays solvent throughout with no principal ever at risk, and the money ends up at the sponsor's own recoveryAddress, which in most pools means a sponsor recovering a bonus they funded themselves. The whitehat's claim on that bonus also only exists because the moderator changed their mind after the fact. Likelihood – Low Four separate things have to coincide: nobody touches the pool for the whole active-risk window (or there are no stakers to begin with), the moderator flags SURVIVED and later reverses to CORRUPTED, that reversal is good-faith with a named attacker, and a sweep lands between the two flags. The first cuts against staker self-interest, since skipping the poke costs them their entire bonus share, and the second asks the moderator to overturn a scope judgement, which is a bigger deal than the typo fix DESIGN.md #4 offers the window for. The sweep itself I'd treat as near-certain once the rest holds, given it's permissionless and the sponsor has an obvious reason to make the call, but assembling the first three in one pool lifecycle is where this stays rare.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
View preliminary resultsAppeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.