A user staking during a pre-risk registry state expects the withdrawal escape hatch to remain available until risk actually begins. A user deliberately entering during UNDER_ATTACK instead accepts immediate lock-up and negligible late-entry bonus weight.
stake() does not let the caller distinguish those intents. It reads the registry only at execution and deliberately accepts UNDER_ATTACK. A transaction submitted while the registry is ATTACK_REQUESTED can therefore execute after approval moves the agreement to UNDER_ATTACK; the same call opens riskWindowStart, transfers principal, and permanently disables withdrawal.
Likelihood:
Occurs when a stake remains pending while the registry moderator approves an ATTACK_REQUESTED agreement into UNDER_ATTACK.
Requires transaction ordering that places the normal registry transition before the pending stake.
Impact:
Principal intended to remain withdrawable is converted into locked risk capital without execution-time consent.
The staker must wait for moderator resolution or pool expiry while receiving negligible bonus weight as a late entrant.
Setup: append the function below to test/unit/ConfidencePool.t.sol (same ConfidencePoolTest harness / BaseConfidencePoolTest helpers already used by the suite), then run:
The registry is set to ATTACK_REQUESTED, where deposits and withdrawals are both allowed.
Alice mints and approves 100 * ONE intending a pre-risk stake that remains withdrawable.
Before her pending stake executes, the registry moves to UNDER_ATTACK.
Alice's stake() still succeeds and seals riskWindowStart in the same call.
Alice's immediate withdraw() reverts with WithdrawsDisabled, locking principal she never consented to lock at execution time.
Require explicit consent for an active-risk deposit and support a user deadline.
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.