A ConfidencePool is only meant to exist during the agreement's commitment phase (NOT_DEPLOYED / NEW_DEPLOYMENT) — the exact pair the pool treats as "scope still open." Scope is chosen up front and locks one-way the moment _observePoolState first sees any other state, on the assumption that scope is committed before anyone knows how risk plays out.
initialize performs no lifecycle check. Its only agreement-side validation, isAgreementValid, is a provenance check (was this made by the factory), not a state gate — so a pool can be created against an agreement in any of the five non-commitment states. The impact splits on whether the state permits deposits (_assertDepositsAllowed):
ATTACK_REQUESTED / UNDER_ATTACK — fund-affecting. Deposits are open, so real money enters and the creator picks the covered-account list after learning which contract is under attack. They can exclude that contract; when the agreement is later marked CORRUPTED, the moderator resolves SURVIVED via the "breach outside this pool's scope" branch (https://github.com/CodeHawks-Contests/2026-07-bc-confidence-pools/blob/58e8ba4ce3f3277866e4926f3140e597f9554a1e/src/ConfidencePool.sol#L334-L340), refunds stakers in full, and pays whitehats nothing.
PROMOTION_REQUESTED / PRODUCTION / CORRUPTED — Deposits are gated shut, so no funds at risk, but the pool still deploys, advertises a scope, and reports UNRESOLVED — misleading indexers/UIs and enabling spam.
Likelihood:
Reasonably likely for the fund-affecting states — any creator can deploy at will; the only precondition is the agreement being in ATTACK_REQUESTED / UNDER_ATTACK, which requires no race or privilege. The escape uses only intended flows (initialize → stake → flagOutcome(SURVIVED)); nothing reverts.
Impact:
Live-pool abuse denies whitehats a bounty they staked/hunted against while refunding stakers in full — value redirected by a decision made with hindsight.
Zombie pools cause no fund loss but misrepresent on-chain state to participants and indexers, and enable spam.
test/unit/ConfidencePool.deployStateGate.t.sol (run forge test --match-path "deployStateGate"). The matrix test walks all seven states, proving initialize never reverts and mapping which states let funds in:
Results:
One check closes all five bad states. agreement is assigned before _replaceScope, so _getAgreementState() is already callable:
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.