Describe the normal behavior in one or more sentences
The sponsor controls recoveryAddress - the address that receives all staker funds in a bad-faith CORRUPTED outcome. The contract locks expiry after the first stake and locks scope once the registry leaves pre-attack staging to protect stakers from parameter changes after they deposit.
Explain the specific issue or problem in one or more sentences
setRecoveryAddress() has no equivalent lock. The sponsor can change recoveryAddress after the moderator flags CORRUPTED and before claimCorrupted() is called, redirecting the entire pool to an address they control.
Likelihood:
Reason 1 // Describe WHEN this will occur (avoid using "if" statements)
The sponsor calls setRecoveryAddress() in the window between the moderator flagging CORRUPTED and the first claimCorrupted() call - no timelock, no delay, and no on-chain mechanism prevents this
Reason 2
claimCorrupted() has no access control and can be triggered by anyone, so the sponsor simply redirects the address first and the sweep happens automatically
Impact:
Impact 1
All staker principal and bonus is swept to the sponsor's wallet instead of the address stakers verified before depositing - complete loss of funds in the bad-faith CORRUPTED scenario
Impact 2
The bad-faith CORRUPTED punishment mechanism is fully bypassed - the sponsor who caused or failed to prevent the corruption controls where the punishment funds go
The following test demonstrates the attack. Place in test/unit/ and run with forge test --match-test test_RecoveryAddressRedirectAfterCorrupted -vv
Lock recoveryAddress once the outcome is set, matching the same pattern used for expiry and scope.
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.