The pool intends to make its account scope immutable after the Agreement leaves pre-attack
staging. In ATTACK_REQUESTED, both explicit observation paths revert after writing
scopeLocked = true, so EVM rollback erases the lock. After a normal registry rejection returns
the Agreement to NOT_DEPLOYED, the sponsor can replace the scope of an already-funded pool.
Existing staker principal can later fund a CORRUPTED payout for a replacement account that those
stakers did not deposit against.
_observePoolState() correctly attempts to lock in ATTACK_REQUESTED:
Both available lock-only calls then revert:
ATTACK_REQUESTED does not set either risk marker. setPoolScope() therefore reverts because it
just set the lock, while pokeRiskWindow() reverts because only the lock changed. Both transactions
leave scopeLocked == false.
The upstream rejectAttackRequest() function explicitly deletes the registration and returns the
Agreement to NOT_DEPLOYED. The sponsor can then call setPoolScope() successfully, provided the
replacement account is in the Agreement's scope. A later approved attack lifecycle and moderator
CORRUPTED decision pays the pool according to the replacement commitment.
Sponsor pause strengthens the path by disabling stake() and contributeBonus(), which otherwise
could incidentally persist the lock. withdraw() remains available and would persist the lock, so
stakers can reduce the risk by monitoring and exiting; this is why likelihood is Low.
Occurs when a funded pool reaches ATTACK_REQUESTED before any successful call persists its scope lock.
Occurs when the registry moderator rejects the request back to NOT_DEPLOYED.
Occurs when the sponsor replaces the scope before a later approved attack lifecycle.
Occurs when the replacement scope is later judged CORRUPTED.
Occurs when no successful stake, bonus contribution, or withdrawal persists the lock during the request window, which makes likelihood Low.
Existing stakers can lose all principal and bonus against a replacement account set.
The sponsor changes the relied-upon commitment after the Agreement already left pre-attack staging.
The maximum loss is the entire balance of each affected pool.
Use the primary PoC embedded below. If the reviewer wants to run it, save the code as test/poc/CodexRebuilt_20260712_AttackRequestedScopeLockRollback.t.sol in the target repository and run:
Observed at commit 58e8ba4ce3f3277866e4926f3140e597f9554a1e:
The test funds the original scope, proves both observation calls roll back their lock writes,
models the upstream rejection to NOT_DEPLOYED, replaces the funded scope, and then pays the full
pool on a later replacement-scope corruption. The paused-pool variant is supporting evidence for the same root cause and is not a separate finding.
File: CodexRebuilt_20260712_AttackRequestedScopeLockRollback.t.sol
Treat a newly persisted scope lock as a successful observation even when no risk-window timestamp
was created:
Add a regression test for ATTACK_REQUESTED -> rejectAttackRequest -> NOT_DEPLOYED and assert that
the pool-local scope remains immutable after rejection, including while the pool is paused.
Impact - Low Nothing moves when the scope is swapped, and the state afterward is pre-attack, so any staker who notices can withdraw in full. _replaceScope emits ScopeUpdated, which puts the change on-chain where it can be seen. Real loss needs a restarted attack cycle that breaches one of the substituted accounts with the original staker still in the pool, at which point their principal funds a CORRUPTED payout for coverage they never chose. Likelihood - Medium The step the sponsor cannot force is the moderator rejecting the attack request, though rejections are an ordinary registry operation. The rest they can arrange. Neither observation path can seal the lock in this state, and pausing the pool shuts the deposit routes, leaving only a full-exit withdraw to do it. So reaching the mutable-scope condition is not hard; what holds the severity down is how much has to go wrong afterward for anyone to actually lose money.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
View preliminary resultsAppeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.