recoveryAddress can be changed by the pool owner at any time, including after a terminal outcome has fixed the economic allocation. claimCorrupted(), sweepUnclaimedCorrupted(), and sweepUnclaimedBonus() read the live storage value when they transfer funds rather than a recipient captured at resolution.
A compromised or malicious owner can therefore wait until users and keepers observe a settled CORRUPTED, SURVIVED, or EXPIRED pool, replace the recipient, and redirect the pending sweep. In the bad-faith CORRUPTED case, this redirects the entire pool balance, including all staker principal and bonus.
The setter is restricted only by owner authentication and a zero-address check:
No resolution function stores the then-current recipient. Each sweep dereferences the mutable value immediately before the external transfer:
This creates a transaction-ordering surface. A keeper can submit a permissionless sweep to the public mempool; the owner can front-run it with setRecoveryAddress(attacker), causing the keeper's otherwise valid transaction to execute against the replacement. No additional confirmation, delay, or participant veto exists.
The owner is an explicit trusted sponsor under the design, which bounds the likelihood. However, post-resolution mutability is stronger than ordinary pre-funding configuration authority because it can alter the destination after the outcome and recoverable amount are already known. Ownable2Step protects ownership transfers but does not mitigate compromise of the accepted owner.
Likelihood:
Only the pool owner can change the address, so exploitation requires sponsor malice, key compromise, or an operational mistake.
The path is available in every lifecycle state and can be executed immediately before any permissionless sweep.
High-value settled pools and public sweep transactions make the redirection opportunity easy to identify once owner authority is compromised.
Impact:
In bad-faith CORRUPTED pools, all principal and bonus can be redirected from the recipient users observed at resolution.
In good-faith CORRUPTED and SURVIVED/EXPIRED pools, remaining bounty, unclaimed bonus, dust, and donations can be redirected.
Events emitted by the original resolution do not commit a recipient, so off-chain expectations cannot enforce the earlier value.
Create test/audit/CP054MutableRecoveryAfterResolution.t.sol with the following contents:
Run the PoC from the repository root:
Execute forge test --offline --match-path test/audit/CP054MutableRecoveryAfterResolution.t.sol -vv.
Confirm that the test passes. The pool is settled as bad-faith CORRUPTED with a 150-token balance, the owner changes the recovery address afterward, and the full balance goes to the replacement while the original recipient receives nothing.
Snapshot the recovery recipient whenever an outcome is first resolved and use the snapshot for all value associated with that settlement. Also prevent the ordinary setter from changing settlement routing after resolution. If a broken or blacklisted recipient must remain repairable, expose a separate timelocked governance process with explicit old/new recipient events and sufficient delay for monitoring and cancellation.
Apply the same snapshot to both unclaimed-corrupted and bonus sweeps. Snapshot updates during an allowed pre-claim moderator re-flag should follow a documented rule; the safest approach is to retain the recipient captured by the first terminal outcome unless governance deliberately executes the delayed recovery-repair process.
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.