The pool maintains O(1) time-weighted bonus-accounting accumulators. Before the risk window opens, stake() records each deposit using the current timestamp. On the first observation of UNDER_ATTACK or PROMOTION_REQUESTED, _markRiskWindowStart() resets the global accumulators so all existing eligible stake is treated as entering at the observed risk-window timestamp.
stake() only proves that the amount is safe for multiplication at the deposit timestamp. It does not reserve arithmetic headroom for the later, larger riskWindowStart timestamp. Consequently, a stake that is accepted before the risk window can make _markRiskWindowStart() overflow later. Every call that tries to observe the active-risk state then reverts, including pokeRiskWindow() and the expiry settlement path.
Likelihood:
The factory accepts any owner-approved standard ERC-20 and imposes no on-chain maximum on raw token supply, token decimals, or aggregate pool stake. A standards-compliant high-decimal/high-supply token can provide the required raw amount without fee, rebase, or callback behavior.
UNDER_ATTACK and PROMOTION_REQUESTED are normal active-risk lifecycle states, not exceptional breach states. A stake accepted before this state can cross the multiplication boundary after time advances and the risk window is first observed.
The triggering stake is approximately 3.77e58 raw units. This is representable by a standard ERC-20 with a sufficiently high decimal precision or supply. Therefore, likelihood is low for conventional assets and meaningful for any approved asset without a conservative raw-unit bound.
Impact:
The first active-risk observation reverts. pokeRiskWindow() cannot seal the window; deposits and bonus contributions also fail because they observe state before proceeding.
When the pool reaches expiry while still in an active-risk state, claimExpired() should resolve EXPIRED and return staker principal plus bonus. Instead, it reverts during state observation, temporarily locking the pool’s stake and bonus until the registry reaches a terminal state without a successful active-risk observation.
A staker can poison the full pool’s settlement liveness with one accepted deposit. The attack does not steal funds and also leaves the attacker’s stake locked; nevertheless, it disrupts the protocol’s normal expiry guarantee for every participant. This supports Medium severity where full-pool, attacker-triggered settlement DoS
Create a new test file: test/unit/ConfidencePool.arithmetic.t.sol
Add this test below:
Enforce a maximum aggregate raw stake that is safe for the entire pool lifetime, not merely safe at the deposit timestamp. The factor of two also preserves headroom for the two positive terms added in _bonusShare.
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.