Before the first claim, the moderator may correct a previously flagged outcome. When the corrected outcome is good-faith CORRUPTED, the named whitehat should receive the entire pool recorded as snapshotTotalStaked + snapshotTotalBonus.
However, sweepUnclaimedBonus() permits any address to transfer tracked bonus to recoveryAddress while the correction window remains open. The function decreases totalBonus but intentionally leaves claimsStarted unset. A subsequent correction therefore remains valid, but flagOutcome() re-snapshots the reduced totalBonus, permanently decreasing the whitehat's bounty.
The issue is not permissionless sweeping by itself. The issue is that tracked bonus is considered sweepable while a corrected distribution requiring that bonus remains reachable.
Likelihood: Medium
This occurs during the documented correction window when a pool containing tracked bonus is initially flagged SURVIVED, no risk window was locally observed, and the moderator subsequently corrects the outcome to good-faith CORRUPTED.
Any address can monitor OutcomeFlagged and call sweepUnclaimedBonus() before the moderator submits the correction. The caller requires no capital, privileged role, token approval, or existing pool position.
The required moderator action is an ordinary correction explicitly supported by the protocol, rather than malicious privileged behavior.
Impact: Medium
The entire tracked bonus can be transferred to recoveryAddress instead of the named good-faith reporter.
The corrected bountyEntitlement is permanently reduced because the correction snapshots the already-decreased totalBonus.
The permissionless caller does not receive the funds directly, but can cause a quantified and irreversible loss of whitehat rewards.
In the demonstrated scenario, the whitehat receives 100 tokens instead of 150 tokens, losing the complete 50-token bonus.
The PoC proceeds as follows:
Both pools receive 100 tokens of eligible stake and 50 tokens of tracked bonus.
The mock registry is placed in the terminal CORRUPTED state while riskWindowStart remains zero, representing a pool that never locally observed the active-risk interval.
In the control pool, the moderator first flags SURVIVED and then corrects it to good-faith CORRUPTED before any sweep. The resulting bountyEntitlement is 150 tokens, and the named whitehat successfully receives all 150 tokens.
In the attacked pool, the moderator first flags the same SURVIVED outcome. Before the correction transaction, an arbitrary address calls sweepUnclaimedBonus(). Because no risk window was observed, the function treats the entire 50-token tracked bonus as unreserved and transfers it to recoveryAddress.
The sweep does not set claimsStarted, so the moderator can still perform the documented correction to good-faith CORRUPTED. During this correction, flagOutcome() snapshots the now-zero totalBonus, reducing bountyEntitlement to 100 tokens.
The final assertions prove that the control whitehat receives 150 tokens while the attacked-pool whitehat receives only 100 tokens. The 50-token difference is caused solely by the permissionless pre-correction sweep.
The permissionless caller receives no direct profit and requires no capital or role. The demonstrated security impact is the irreversible diversion of the complete tracked bonus away from the good-faith reporter.
While claimsStarted == false, reserve all tracked bonus because a correction to good-faith CORRUPTED remains reachable. Permissionless sweeping may continue to recover direct-transfer donations, but it must not remove totalBonus until the correction window has closed.
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.