According to DESIGN.md, the pool's scope is a fixed commitment, and stakers deposit funds under the strict invariant that their "exposure is bounded by what they signed up for at deposit time."
The setPoolScope function completely fails to enforce this invariant because it lacks a stake-based lock. While the expiry parameter correctly locks on the first deposit via expiryLocked, setPoolScope only locks when the BattleChain registry transitions out of its NEW_DEPLOYMENT / NOT_DEPLOYED staging states. This allows a malicious sponsor to front-run the registry transition to UNDER_ATTACK with a call to setPoolScope, swapping the scope to a highly vulnerable or already-breached contract right as the exit door (withdraw()) permanently closes, trapping the stakers.
This violates the explicit invariant in DESIGN.md §8: “stakers’ exposure is bounded by what they signed up for at deposit time.”
Likelihood:
A malicious sponsor observes a highly vulnerable or breached contract that is NOT in the pool's current scope.
The sponsor monitors the mempool for the BattleChain registry's state transition to UNDER_ATTACK and perfectly front-runs it with a setPoolScope transaction to include the breached contract.
Impact:
Stakers are permanently trapped underwriting a completely different, fraudulent risk profile than the one they reviewed and agreed to at deposit time.
The sponsor fraudulently guarantees a CORRUPTED outcome, effectively stealing the stakers' principal and bonus.
The PoC demonstrates how a malicious Sponsor can exploit the missing stake-based lock on setPoolScope to trap stakers.
The Sponsor seeds the pool with a benign SafeContract scope.
Alice reviews the safe scope and deposits her funds.
When the BattleChain registry transitions to UNDER_ATTACK, the Sponsor front-runs the transition with a call to setPoolScope, swapping the scope to a HighlyVulnerableContract.
Because the registry is still in NEW_DEPLOYMENT when the Sponsor's transaction executes, the scopeLocked check is bypassed.
The UNDER_ATTACK transition lands immediately after, permanently disabling withdrawals (WithdrawsDisabled) and trapping Alice in a fraudulent scope she never agreed to.
To ensure stakers' exposure remains strictly bounded by what they signed up for, setPoolScope must be locked upon the first stake. We recommend utilizing the existing expiryLocked latch, which is permanently set to true on the very first deposit.
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.