Under a bad-faith CORRUPTED resolution the whole pool sweeps to recoveryAddress. The moderator flags the outcome (flagOutcome, src/ConfidencePool.sol:331), and then claimCorrupted (:420) or, on the good-faith path after the claim window lapses, sweepUnclaimedCorrupted (:470) transfers the pool's live balance to recoveryAddress. DESIGN.md sec.10 states this destination "receives the full pool (including stakers' principal) under bad-faith CORRUPTED", so recoveryAddress is the single address that decides where every staker's principal lands once the outcome is terminal.
The sponsor sets that destination through setRecoveryAddress (src/ConfidencePool.sol:631). The only guard is onlyOwner plus a zero-address check. There is no timelock, no two-step handover, and no lock tied to the resolution state. The contract locks expiry on the first stake through the expiryLocked one-way latch precisely to protect staker reliance (DESIGN.md sec.10, "sponsor-mutable only until the first stake"), but the equally staker-relevant recoveryAddress gets no equivalent latch. It stays fully mutable up to and after the outcome is flagged, right through the window before the sweep executes. So an owner key (or a key an attacker has compromised) can repoint the sweep destination after flagOutcome has already committed the whole pool to a bad-faith CORRUPTED distribution, and the next claimCorrupted/sweepUnclaimedCorrupted pays the newly-pointed address. The sponsor's own inline note flags this at src/ConfidencePool.sol:628 (//audit-low).
This sits inside the documented sponsor-trust model (DESIGN.md sec.10), so it is not an unexpected-actor break. The sharp edge is the missing delay and the post-resolution mutability: the redirect can happen after the outcome is already terminal, when stakers can no longer withdraw and have no reaction window, and a single owner transaction moves 100% of the principal to an attacker-chosen address.
Likelihood:
Requires the owner (sponsor) key to sign the repoint. Rated Low because it is a trusted role, but the key-compromise / insider case is exactly what a lock would defend against and no lock exists.
Fires only in a bad-faith CORRUPTED (or lapsed good-faith CORRUPTED) resolution, which is a subset of pool lifecycles.
The mutation is a single transaction with no delay, so once the key acts there is no window for stakers to notice or react.
Impact:
The full pool, including every staker's principal plus the bonus contributions, is redirected to an attacker-chosen address instead of the sponsor-published recovery address.
The redirect happens after the outcome is terminal, when stakers can no longer withdraw, so there is no staker mitigation available on-chain.
Affects both sweep paths: claimCorrupted (bad-faith) and sweepUnclaimedCorrupted (good-faith remainder after the claim window).
The test uses the project's own BaseConfidencePoolTest harness: _stake deposits real principal, _passThroughUnderAttack seals riskWindowStart, and the mock registry is driven to terminal CORRUPTED so the moderator can flag a bad-faith outcome. After the outcome is terminal, the owner calls setRecoveryAddress(newRecovery) and then claimCorrupted fires: the assertions prove the original sponsor recovery address receives zero and the full principal lands at the repointed attacker address.
Output (forge test --match-contract RecoveryRedirect -vv, forge 1.7.1, commit 58e8ba4):
Lock recoveryAddress once the pool has resolved (mirroring the expiryLocked latch the sponsor already applies to expiry), and/or route changes through a timelocked two-step handover so a repoint cannot take effect inside the flag-to-sweep window:
The single if (outcome != PoolStates.Outcome.UNRESOLVED) revert guard closes the post-resolution redirect window on its own; a timelocked two-step is defense-in-depth against a pre-resolution key compromise.
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.