The pool owner may modify the covered accounts only during NOT_DEPLOYED or NEW_DEPLOYMENT. Observing any later registry state must set scopeLocked permanently, protecting the coverage commitment made to stakers.
During ATTACK_REQUESTED, _observePoolState() sets scopeLocked = true. However, this state does not set riskWindowStart or riskWindowEnd, causing pokeRiskWindow() to revert and roll back the scope lock. When the registry subsequently rejects the attack request and returns to NOT_DEPLOYED, the owner can replace the pool scope.
Likelihood:
This occurs when the registry reaches ATTACK_REQUESTED, no successful stake, withdrawal, or bonus contribution persists the scope lock, and a caller uses pokeRiskWindow().
The exploitable window appears when the registry moderator subsequently rejects the attack request, returning the agreement to NOT_DEPLOYED, after which the pool owner replaces the scope.
Impact:
Existing stakers lose the permanent scope commitment they expected once the agreement passed pre-attack staging.
The owner can broaden or narrow coverage, potentially changing a future breach from SURVIVED to CORRUPTED or vice versa. This can change the destination of the entire pool’s principal and bonus.
Add the following test to ConfidencePool.scope.t.sol:
Treat persisting the scope lock as a successful observation, even when neither risk-window timestamp was created:
This allows an ATTACK_REQUESTED observation to complete and permanently store scopeLocked = true, while calls during NOT_DEPLOYED and NEW_DEPLOYMENT continue reverting as before.
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.