The pool is intended to distribute the bonus according to each staker's quadratic time-weighted score:
After the pool resolves as SURVIVED or EXPIRED, every eligible staker should be able to recover their principal plus their calculated share of the bonus.
However, the contract expands the quadratic formula using several checked uint256 multiplications involving absolute Unix timestamps. The protocol does not impose an upper bound on the token's decimals, raw token supply, individual stake size, or aggregate stake size.
A sufficiently large but valid ERC-20 deposit can therefore be accepted during stake(), while later causing _bonusShare() to revert from arithmetic overflow when a larger timestamp T is used at claim time.
The deposit accounting stores the following timestamp moments:
When a staker claims, _bonusShare() evaluates the expanded polynomial using the later upper-bound timestamp T:
Math.mulDiv() cannot protect these calculations because the overflow occurs before mulDiv() is called.
An attacker can select a stake amount A such that:
where:
S is the earlier entry or risk-window timestamp;
T is the later resolution timestamp;
T > S.
Consequently, the attacker's deposit and the opening of the risk window can succeed, but all subsequent bonus-share calculations revert.
Once the risk window has opened, withdraw() is permanently disabled. After resolution, the pool also cannot return to the unresolved state. Therefore, affected stakers have no alternative route through which to recover their principal.
The repository explicitly supports standard ERC-20 tokens but does not restrict token decimals or maximum raw balances. A high-decimal ERC-20 can make the required raw amount economically small while still triggering the overflow. fileciteturn3file0L1-L1
An attacker can permanently deny all SURVIVED or EXPIRED claims in the affected pool.
The consequences are:
honest stakers cannot recover their principal;
honest stakers cannot recover their bonus entitlement;
the attacker's own stake is also locked, but the economic cost can be small when using a high-decimal token;
withdrawals cannot be reopened after the risk window starts;
the resolved outcome cannot be reset after claims begin;
the pool balance may remain permanently inaccessible.
Because this can freeze all principal and bonus held by a pool, the impact is High.
The attack requires the pool factory owner to allowlist an ERC-20 whose raw balances can reach the required magnitude, such as a token with unusually high decimals or supply.
The factory allowlist lowers the likelihood, but the implementation does not enforce any decimal, supply, or maximum-stake restriction itself. A token can also remain ERC-20 compliant while using high decimals.
Therefore, the likelihood is assessed as Medium.
Add the following test to a test contract inheriting BaseConfidencePoolTest:
The exact amount may need to be selected using the test's risk-window and resolution timestamps so that the earlier timestamp-square calculation succeeds while the later one overflows.
Avoid evaluating the quadratic score using absolute Unix timestamps.
Store and calculate time relative to riskWindowStart:
This substantially reduces the timestamp magnitude used in the intermediate calculations.
Additionally, enforce a maximum individual and aggregate stake that guarantees every score expression remains within uint256 for the worst-case timestamp.
For example, before accepting a deposit, calculate a conservative maximum based on expiry:
The implementation should also use overflow-safe algebra or 512-bit intermediate arithmetic for the complete score computation, rather than applying Math.mulDiv() only after the potentially overflowing polynomial has already been evaluated.
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.