A stake accepted by ConfidencePool should remain safely claimable through every supported terminal payout path.
However, the pool places no upper bound on individual or aggregate stake. A sufficiently large amount can be accepted because its deposit-time arithmetic still fits within uint256, while the later k=2 bonus calculation overflows when _bonusShare() recomputes the score using the larger terminal timestamp T.
During stake(), the contract records timestamp-weighted values without enforcing a bound that guarantees later claim calculations remain safe:
After resolution, _bonusShare() performs new checked multiplications using the terminal timestamp and the snapshotted pool-wide stake:
There is a concrete range where:
An honest user stakes an ordinary amount.
An attacker adds an oversized stake that is accepted successfully.
The pool successfully observes the active-risk window.
The pool successfully resolves as SURVIVED, or reaches the observed-risk EXPIRED payout path.
The honest user's claim reaches _bonusShare().
The pool-wide score calculation overflows with arithmetic panic 0x11.
Neither the honest user's principal nor bonus is transferred.
The failure affects every claimant because the denominator uses snapshotTotalStaked. The victim does not need to hold an oversized position; another participant can poison the shared calculation for the entire pool.
A permissionless zero-stake keeper can also mechanically resolve the pool as SURVIVED and latch claimsStarted = true before the honest staker claims. The pool is then terminal, but its payout path remains unusable.
This finding is separate from the active-risk observation overflow. Every test relied upon here successfully calls pokeRiskWindow() and records the risk window. The failure occurs later and independently inside _bonusShare() during payout.
Likelihood:
The issue occurs when accepted aggregate stake reaches the range where the later T² × snapshotTotalStaked expressions overflow, while the earlier deposit-time calculations still fit.
The required aggregate amount is extremely large. The PoC uses 2 * 10**58 raw token units, making practical exploitation unlikely for ordinary production assets. The pool nevertheless enforces no supply or stake cap, and the same aggregate can be distributed across multiple attacker-controlled addresses.
Impact:
Honest stakers permanently lose access to principal and bonus through claimSurvived() and observed-risk claimExpired() because the claim reverts before transferring value.
One oversized participant can grief-brick payout for every other staker through the shared global score calculation.
Mechanical expiry resolution can latch finality before users attempt their claims, leaving a terminal pool whose intended payout path remains unusable.
Create test/poc/HugeStakeClaimOverflowFinding12.t.sol with the complete test below:
Run:
The PoC contains only the five tests relevant to this finding:
These branches were already verified as passing in the original combined HugeStakeClaimOverflow.t.sol suite. The isolated file removes only the four unrelated active-risk observation-overflow tests.
The tests prove that:
a 2 * 10**58 stake is accepted successfully;
an honest victim can hold only 1e18;
active-risk observation succeeds;
normal moderator or mechanical terminal resolution succeeds;
the honest claimant later reverts with arithmetic panic inside _bonusShare();
both SURVIVED and observed-risk EXPIRED payout paths are affected;
a zero-stake keeper can latch the poisoned terminal outcome;
splitting the oversized aggregate across 64 attacker addresses produces the same failure.
Enforce a stake bound that guarantees every current and future squared-time intermediate remains within uint256.
For example, the aggregate cap should account for the maximum supported timestamp and the addition of two squared-time terms:
Alternatively, rewrite the expanded k=2 score calculation using bounded full-precision arithmetic and reject deposits whenever future score calculations cannot be represented safely.
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.