The pool owner may update expiry only while expiryLocked is false. The first successful stake sets expiryLocked = true so later stakers can rely on a fixed deadline for staking closure and for the EXPIRED path’s k=2 upper bound T = expiry.
• The latch is never cleared when a staker fully exits via withdraw, even when totalEligibleStake returns to zero and the registry is still pre-attack. Any address can post exactly minStake, immediately withdraw, and permanently freeze setExpiry. That griefs pool setup: the sponsor can no longer extend the underwriting window for subsequent legitimate stakers, despite no capital remaining in the pool.
Likelihood:
A public pool remains in a pre-attack registry state (NOT_DEPLOYED, NEW_DEPLOYMENT, or ATTACK_REQUESTED) with expiry not yet locked, and any address posts minStake then withdraws before the sponsor finalizes the intended term.
• Front-running of the sponsor’s first “real” stake—or opportunistic dust stake while the pool is advertised—permanently trips the latch using only temporary capital equal to minStake.
Impact:
The sponsor can no longer call setExpiry to extend the underwriting window for later cohorts, even when totalEligibleStake == 0 and withdrawals remain open.
• Funds are not stolen, but pool configuration can be griefed into a shorter-than-intended term, harming subsequent stakers who wanted a longer horizon or stranding a pool that still needed a longer expiry before meaningful deposits.
What this PoC proves
Before any stake, the owner can still call setExpiry (baseline: latch off).
Alice stakes only minStake (ONE in the test harness).
expiryLocked flips to true.
Alice fully withdraws while the registry is still pre-attack (allowed path).
expiryLocked remains true despite zero remaining stake.
Owner setExpiry reverts with ExpiryLocked, so the term cannot be extended.
Why the steps matter
• Steps 2–3 show that any successful stake, including dust-sized capital, is enough to arm the permanent latch.
• Step 4 shows the attacker does not need to leave funds at risk—temporary capital is enough.
• Steps 5–6 prove the grief is permanent and on-chain enforceable: sponsor configuration is bricked for the life of the clone.
Goal: Prevent unprivileged dust stakes from permanently freezing sponsor term configuration when no capital remains at risk, without re-introducing the “move expiry under an active cohort” attack that the one-way latch was meant to stop.
Approach (recommended): Keep the latch while any stake is outstanding or while the registry has left pre-attack staging. Clear expiryLocked only when both totalEligibleStake == 0 and the live registry state is still pre-attack. That way:
• A dust griefer who enters and exits before real deposits does not brick setExpiry.
• A sponsor still cannot move expiry while stakers are bonded (original safety property).
• Once risk materializes, the latch stays one-way even if everyone later exits.
Why this fix works
• Breaks the PoC at step 5: after full withdraw with zero remaining stake in pre-attack state, expiryLocked clears and setExpiry succeeds again.
• Does not allow moving expiry while other stakers still have principal in the pool.
• Does not re-open expiry after the pool has left pre-attack staging.
Operational alternative: Keep the permanent latch and document that sponsors must set final expiry before any address can call stake. Prefer the code change above when the product wants pre-deposit configuration flexibility without a grief surface.
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.