Deposit admission depends only on the registry's current state. A registry rewind can therefore admit stake after the pool has permanently recorded active risk or a terminal time, leaving the new principal non-withdrawable and allowing post-terminal stake to capture bonus without bearing risk.
Normally, stake() and contributeBonus() are allowed in the pre-risk states and UNDER_ATTACK, but closed in PROMOTION_REQUESTED, PRODUCTION, and CORRUPTED. Once active risk is observed, riskWindowStart permanently disables withdrawals; once a terminal state is observed, riskWindowEnd permanently fixes the bonus endpoint T.
_assertDepositsAllowed() ignores both local markers and checks only the latest registry value. If a registry migration, replacement, or reset temporarily reports NEW_DEPLOYMENT after riskWindowStart was sealed, a new stake succeeds even though withdraw() remains permanently disabled. If the rewind occurs after riskWindowEnd was sealed, a new stake is recorded with entryTime > T.
The k=2 score is stake * (T - entryTime)^2. The implementation's expanded quadratic remains positive for entryTime > T, so a deposit made after the risk window receives more bonus weight the farther it is from T. An unprivileged depositor can therefore enter during the rewind, wait for the registry to return to PRODUCTION, and claim principal plus bonus despite bearing no pre-T risk. In the PoC, equal-sized stakes are placed one day before and twenty days after T; the post-terminal stake captures over 99% of the bonus.
Likelihood:
The ordinary BattleChain lifecycle is monotonic. This occurs during a registry migration, replacement, reset, or other trusted infrastructure event that temporarily exposes an earlier state to an unresolved pool.
Once such a rewind is visible, any account can deposit; exploiting the bonus path requires only a terminal marker already sealed and enough time remaining before expiry.
Impact:
New principal is accepted after the pool has locally recorded risk, but cannot use the pre-resolution withdrawal path because riskWindowStart remains sealed.
A post-T staker bears no risk during the recorded window yet can capture most of the bonus, directly diluting honest stakers. The share grows with the square of the time elapsed after T.
Create test/audit/CP007RegistryRewindReopensDeposits.t.sol with the following contents:
Run the PoC from the repository root:
Execute forge test --offline --match-path test/audit/CP007RegistryRewindReopensDeposits.t.sol -vv.
Confirm that both tests pass with zero failures.
Make deposit gating respect the pool's monotonic local history. Keep UNDER_ATTACK deposits available as designed, but reject pre-risk registry values after riskWindowStart is set and reject every deposit after riskWindowEnd is set.
Impact - Medium Bonus pool only, principal always returns under SURVIVED/EXPIRED, but the quadratic advantage is unbounded and a tiny late stake can take nearly all of it. Likelihood - Low It needs a DAO registry migration to land inside the window where a pool is unresolved with riskWindowEnd already sealed, and the attacker still has to be watching. No attacker action can create the precondition.
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.