FoundrySolidityLayer 2
7.25 ETH
Submission Details
Impact: medium
Likelihood: medium

setPoolScope guard ordering blocks last-chance scope update

Author Revealed upon completion

Description

_observePoolState() at Pool:638 runs before the scopeLocked guard at Pool:639. Since _observePoolState() has the side effect of setting scopeLocked = true when the registry leaves pre-attack staging (NOT_DEPLOYED/NEW_DEPLOYMENT), the observation inside setPoolScope() self-defeats the intended update.

Pool:636 function setPoolScope(accounts)
Pool:638 _observePoolState() // side effect: may set scopeLocked=true
Pool:639 if (scopeLocked) revert // catches the side effect, reverts
Pool:640 _replaceScope(accounts) // never reached

The lock trigger at Pool:787-792:

if (!scopeLocked && state != NOT_DEPLOYED && state != NEW_DEPLOYMENT) {
scopeLocked = true;
}

Risk

Likelihood: Medium. Any registry transition past pre-attack staging that the pool hasn't yet observed will cause the next setPoolScope() call to self-revert. This includes the common NEW_DEPLOYMENT → ATTACK_REQUESTED transition. A front-running pokeRiskWindow() by anyone can also trigger this.

Impact: Medium. The scope is permanently frozen at its old value. A stale scope causes the moderator to make SURVIVED vs CORRUPTED decisions against an outdated account list — directly affecting fund distribution. DESIGN.md §8 guarantees "the sponsor can update scope freely while the registry is in NOT_DEPLOYED / NEW_DEPLOYMENT" — the ordering bug breaks this guarantee.

Mitigation

Hoist the scopeLocked guard before _observePoolState():

function setPoolScope(address[] calldata accounts) external onlyOwner {
+ if (scopeLocked) revert ScopePostLockImmutable();
_observePoolState();
if (scopeLocked) revert ScopePostLockImmutable();
_replaceScope(accounts);
}

The early guard prevents unnecessary external calls when already locked. The post-observation guard still catches the case where the observation itself triggers the lock — this is correct behavior (scope should lock when the registry leaves staging).

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!