The pool accepts stakes during UNDER_ATTACK until expiry and resolves non-terminal states to EXPIRED at that deadline, returning principal plus bonus. The quadratic bonus formula distributes the entire available bonus by normalizing each staker's score against the global score. When an attacker stakes alone in the final pre-expiry block, any positive score equals the global score and receives 100% of the sponsor-funded bonus. The contract permits this timing because _assertDepositsAllowed() intentionally allows UNDER_ATTACK deposits, and claimExpired() treats an agreement still in UNDER_ATTACK at expiry as EXPIRED, immediately paying principal plus bonus.
Likelihood:
The pool must contain a sponsor-funded bonus and be in UNDER_ATTACK immediately before expiry.
The attacker does not control registry state but can time the final pre-expiry block using standard contract functions.
The simplest path requires no other eligible stakers; with existing stakers, profitability depends on their scores and the attacker's available capital to dominate the denominator.
Impact:
A late staker drains the entire sponsor-funded bonus after one-block exposure when no other eligible stakers exist.
Existing stakers may be diluted when the denominator is small and the attacker stakes enough principal to overwhelm their aggregate score.
The attacker recovers all principal immediately after expiry, leaving the bonus as profit apart from transaction costs.
test/poc/FinalBlockActiveRiskBonusCapturePoC.t.sol:
Command:
forge test --match-path 'test/poc/FinalBlockActiveRiskBonusCapturePoC.t.sol' -vvv
Impact:
The PoC passes and demonstrates that a final-second UNDER_ATTACK staker can stake only the minimum amount, wait until expiry, call claimExpired(), and receive their principal plus the entire sponsor-funded bonus. The control test shows that without the late staker, the same bonus would be sweepable to recovery.
Close bonus eligibility for deposits made after riskWindowStart is set. The simplest fix is to reject UNDER_ATTACK in _assertDepositsAllowed():
Alternatively, continue accepting principal deposits during UNDER_ATTACK but exclude post-risk deposits from bonus accounting, or require a minimum maturation period before bonus eligibility.
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.