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.
View preliminary resultsAppeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.