The pool scope is intended to become immutable once the agreement registry leaves pre-attack staging. pokeRiskWindow() is also documented as a permissionless keeper hook that can observe registry transitions and seal the relevant one-way markers.
The issue is that pokeRiskWindow() calls _observePoolState() and then reverts with RiskWindowNotReached when the registry is ATTACK_REQUESTED. Because the revert rolls back all state changes, the scopeLocked = true write made inside _observePoolState() is not persisted. If the registry later returns to a pre-attack state without any successful pool interaction in between, the owner can still change the scope even though the registry had already left pre-attack staging.
Likelihood:
This occurs when the agreement enters ATTACK_REQUESTED and the only pool observation during that state is a reverting call such as pokeRiskWindow().
This occurs when the registry later returns to NEW_DEPLOYMENT or NOT_DEPLOYED before any successful pool interaction has persisted scopeLocked.
Impact:
The owner can change the pool's scope after the agreement already left pre-attack staging, breaking the stated scope immutability point.
Existing stakers may have committed funds under one published scope while a different scope is later installed.
Add this test to test/unit/ConfidencePool.scope.t.sol:
Run:
Expected result:
Allow pokeRiskWindow() to succeed when it observes and persists a scope lock, even when no risk-window marker is sealed.
Alternatively, document that scope locking only persists after a successful pool transaction and does not necessarily happen at the first attempted observation.
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.