Normally, the permissionless auto-CORRUPTED backstop in claimExpired defers to the moderator for MODERATOR_CORRUPTED_GRACE (180 days) so the DAO can flag the good-faith outcome and name the whitehat before anyone finalizes bad-faith CORRUPTED.
The grace window is measured from the pool's fixed expiry rather than from when the registry is first observed CORRUPTED, so when a breach is first observed on-chain only after expiry + 180d the moderator is given zero grace and a permissionless claimExpired front-run finalizes bad-faith CORRUPTED before the moderator can flag good-faith, denying the whitehat bounty.
The moderator cannot pre-empt this by flagging early: flagOutcome(CORRUPTED, ...) requires the live registry state to already be CORRUPTED (src/ConfidencePool.sol:344), which is only true at T_corrupt. When T_corrupt > expiry + 180d, that moment is already past the grace gate.
Likelihood:
The registry first reaches CORRUPTED only after expiry + MODERATOR_CORRUPTED_GRACE has elapsed — a breach discovered late relative to a long-lived pool, which is realistic for vulnerabilities that surface months/years after a pool expires.
A permissionless caller (the sponsor with recoveryAddress set to self per DESIGN.md §10, or any searcher) lands claimExpired in an earlier block than the moderator's good-faith flagOutcome; for this late-observed edge the moderator has no grace buffer to fall back on, unlike an in-window breach where claimExpired reverts AgreementCorruptedAwaitingModerator.
Impact:
The good-faith whitehat bounty (the entire pool per DESIGN.md §12) is denied; claimCorrupted() sweeps the full pool to recoveryAddress instead of to the named whitehat.
Stakers are not additionally harmed versus any CORRUPTED resolution — CORRUPTED pays stakers zero by design — so the marginal loss is borne by the whitehat / protocol incentive, not by stakers.
Run: forge test --match-path test/poc/LateBreachGraceGap.t.sol -vv (PASS). Also confirmed against the live BattleChain testnet fork: BATTLECHAIN_TESTNET_RPC=https://testnet.battlechain.com forge test --match-path 'test/fork/LateBreachGraceGap.fork.t.sol' -vv (2 PASS).
Anchor the moderator grace to the first on-chain observation of CORRUPTED (already tracked when a terminal state is sealed) instead of to expiry, preserving the §6 permanently-absent-moderator backstop:
Impact - High The mechanical branch always picks bad-faith, so the whole corpus lands at recoveryAddress and claimsStarted makes it permanent in the same call. Both alternatives it forecloses send the money elsewhere: DESIGN.md #8 lets the moderator flag SURVIVED for an out-of-scope breach, returning everything to stakers, and good-faith CORRUPTED reserves the pool for a named whitehat. Losing the classification decides who gets paid. Likelihood - Low The pool has to sit unresolved through the whole window past expiry, which is the hard part, since claimExpired stays permissionless throughout and would settle it as EXPIRED against the live active-risk state. Any staker with principal waiting has reason to make that call. Once corruption does land late, the moderator's first legal moment to classify and the fallback's first to finalize arrive together, so ordering alone decides it.
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.