The single claimsStarted flag represents both economic reliance and mechanical resolution finality, but different entrypoints latch it under different conditions. A value-moving bonus sweep leaves re-flagging open, a zero-value expiry resolver closes it, and zero-payout bounty calls leave it open, making correction finality depend on which permissionless transaction executes first.
The moderator may correct an already-flagged outcome until claimsStarted becomes true. The stated rationale is to allow typo correction before anyone relies on the old distribution, then make the first value movement final.
The implementation follows that rule for ordinary claims and nonzero bounty payments, but not uniformly. sweepUnclaimedBonus() can transfer tracked bonus and reduce totalBonus without setting the latch. Conversely, the first claimExpired() sets it during mechanical resolution even when the caller owns no stake and receives nothing. These choices may each be defensible in isolation, but one boolean no longer communicates or enforces a consistent finality invariant.
As a result, transaction ordering can decide whether the moderator can correct the outcome. A beneficiary can close the window with a real claim before a pending correction; a permissionless bonus sweep can move tracked value yet still allow a later outcome rewrite; and any zero-stake expiry caller can finalize the outcome without economic reliance. The current behavior is partly documented as intentional, so this is a policy/finality inconsistency rather than an access-control bypass.
Likelihood:
The issue matters when an initial outcome needs correction and a claim, sweep, bounty call, or expiry resolution is executed before the moderator's corrective transaction.
Exploitation is timing-dependent and usually requires observing a pending correction or a delayed moderator, while the registry state must also permit the desired replacement outcome.
Impact:
Closing the window first can permanently preserve an erroneous outcome and its complete stake/bonus distribution.
Leaving the window open after tracked value moves lets a later re-flag snapshot reduced accounting, underfund a corrected bounty, or otherwise produce a distribution inconsistent with pre-sweep expectations.
Create test/audit/CP034ClaimsStartedFinalityEdges.t.sol with the following contents:
Run the PoC from the repository root:
Execute forge test --offline --match-path test/audit/CP034ClaimsStartedFinalityEdges.t.sol -vv.
Confirm that all four tests pass and demonstrate the open/closed re-flag states after tracked bonus movement, zero-value mechanical resolution, zero-payout bounty execution, and an ordinary value-moving claim.
Separate mechanical resolution finality from economic-reliance finality. Latch economic action only when protocol-accounted value moves, so a direct 1-wei donation cannot grief correction, but sweeping tracked bonus does close the window.
Update ordinary claims, corrupted sweeps, and nonzero bounty transfers to set economicActionStarted; leave genuine zero-payout calls unlatching. If the intended policy is instead “no correction after any successful post-resolution call,” encode that rule explicitly and accept the 1-wei donation grief tradeoff.
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.