Affected: ConfidencePool.sol:222-227 · ConfidencePool.sol:727-733 · ConfidencePool.sol:784-799
stake() and contributeBonus() observe registry state before enforcing their deposit gate. _observePoolState() writes riskWindowStart and scopeLocked as one-way transitions, then _assertDepositsAllowed() reverts on PROMOTION_REQUESTED, PRODUCTION, or CORRUPTED. EVM atomicity rolls the writes back with the revert, so the pool never persists the first observation.
A permissionless caller (Bob) can therefore attempt stake(1 wei) during PROMOTION_REQUESTED and knowingly force the revert; the latches that _observePoolState() would have sealed are lost. Combined with a later legitimate DAO setAttackRegistry migration that reports NOT_DEPLOYED for the agreement, the withdraw() gate re-opens for previously staked capital — even though active risk was already publicly observable on-chain.
Same root cause as M-3, distinct entrypoint: here the failed sealing is triggered by an unprivileged Bob rather than by the observation ordering of a low-traffic pool.
Likelihood: Requires two events — permissionless reverting deposit (or bonus) call during active risk, plus a later routine DAO registry migration (DESIGN.md §11 treats migration as expected).
Impact: Existing staker exits principal after active-risk was on-chain. Bounded per-staker; aggregate up to totalEligibleStake. No attacker capture — this is a leak vs. the intended commitment invariant, not a direct value transfer to the attacker.
Actor: Bob (revert trigger) is fully permissionless. The migration is the DAO's documented onlyOwner operation.
When a deposit is blocked, persist the transition instead of reverting the whole transaction. A seal-only-return pattern preserves the one-way observation without accepting the deposit:
Apply the same rule to contributeBonus(). Alternatively, harden the withdraw gate as recommended in M-3 (|| riskWindowEnd != 0) plus store scopeLocked durably via a dedicated sealObservation() no-op path.
Save as test/ObserverRevertRollback.t.sol and run forge test --match-contract ObserverRevertRollbackTest -vv.
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.