When the registry first enters an active-risk state, ConfidencePool is supposed to latch riskWindowStart and reset the global stake-time accumulators. This observed-risk latch is later used by the permissionless claimExpired() backstop to distinguish a real observed-risk CORRUPTED agreement from the no-risk fallback.
The issue is that _markRiskWindowStart() multiplies the full live stake by an absolute timestamp squared. A sufficiently large but valid ERC20 stake can be accepted before risk starts, then make every later active-risk observation revert with arithmetic overflow. As a result, riskWindowStart remains zero, and a later CORRUPTED agreement can fall through to EXPIRED instead of the intended auto-CORRUPTED backstop.
Likelihood:
This occurs when a pool uses a standard ERC20 with a very large supply/decimals and a staker deposits an amount large enough that totalEligibleStake * block.timestamp ** 2 is near type(uint256).max.
This occurs when the active-risk state is first observed after that large stake was accepted, because _markRiskWindowStart() is evaluated by pokeRiskWindow(), stake(), contributeBonus(), withdraw(), flagOutcome(), or claimExpired().
Impact:
The observed-risk latch can become permanently unsealable while the registry is active-risk, disabling the permissionless auto-CORRUPTED backstop.
A staker with the large position can recover principal through EXPIRED after the agreement becomes CORRUPTED, instead of having the position swept to recoveryAddress.
Add this test to test/unit/ConfidencePool.k2Bonus.t.sol:
Run:
Expected result:
The test passes because the active-risk observation reverts in _markRiskWindowStart(), leaving riskWindowStart == 0. The later claimExpired() call then skips the auto-CORRUPTED branch and resolves as EXPIRED.
Cap the maximum tracked stake so the timestamp-squared accounting cannot overflow.
Alternatively, refactor the accounting to store risk-window-relative time offsets instead of absolute timestamp-squared values.
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.