The pool stops accepting stake at expiry and exposes claimExpired() after that timestamp. The risk-window bookkeeping is intended to measure registry risk observed during the pool term, while the 180-day MODERATOR_CORRUPTED_GRACE permits mechanical settlement when the outcome moderator remains unavailable. The contract does not preserve a strict temporal boundary at expiry. A first active-risk observation made after expiry still initializes riskWindowStart because _markRiskWindowStart() replaces the real observation time with expiry. This makes post-expiry risk indistinguishable from risk observed exactly at the term boundary.
An unresolved pool whose risk window opened before expiry is also affected. claimExpired() checks only the registry's current CORRUPTED state and a nonzero riskWindowStart; it does not establish that corruption occurred before expiry. Corruption first occurring after the covered term therefore selects the same bad-faith CORRUPTED outcome as an in-term corruption. Once the grace period has elapsed, anyone can execute the transition and then call claimCorrupted(). The entire pool balance, including third-party principal and bonus, is transferred to recoveryAddress. The repository documents that settlement reads live registry state, but it does not expressly disclose that risk and corruption beginning only after expiry can confiscate principal from an expired pool. This finding assumes expiry is intended to end the covered risk term. A protocol decision that expiry merely opens settlement while later events remain covered would instead make this an economically significant design choice.
Likelihood:
An unresolved pool remains open beyond expiry + MODERATOR_CORRUPTED_GRACE, while the pool outcome moderator does not finalize an outcome during the grace period.
The registry first enters UNDER_ATTACK or PROMOTION_REQUESTED after expiry and a permissionless pokeRiskWindow() call records the late risk window at the capped expiry timestamp. Alternatively, the pool observes active risk during its term and the registry first becomes CORRUPTED after expiry, before anybody resolves the pool as EXPIRED. Any account can execute pokeRiskWindow(), claimExpired(), and claimCorrupted(); exploitation does not require pool-owner or outcome-moderator permission once the registry states and grace-period conditions exist. Prompt staker settlement at expiry prevents the later transition, reducing likelihood but creating a race around a safety property that should be enforced by contract state rather than user monitoring.
Impact:
Every staker loses all eligible principal after the pool is mechanically finalized as bad-faith CORRUPTED. The complete bonus balance is transferred with the principal, allowing the recovery destination to receive the pool's entire token balance. The final CORRUPTED outcome sets claimsStarted and prevents stakers from using the EXPIRED claim path that would otherwise return their principal.
Reject first active-risk observations made after expiry and retain an uncapped observation timestamp for terminal states. Auto-CORRUPTED settlement should require evidence that the terminal state existed during the covered term.
An authoritative transition timestamp supplied by the registry is preferable. A local observation timestamp is conservative because corruption occurring before expiry but first observed afterward would not qualify automatically; such cases can remain subject to independent moderator resolution.
Merely requiring riskWindowEnd <= expiry does not fix the issue. The current implementation already caps late observations to expiry, so that condition is true even when corruption is first observed long after the term ended
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.