Integer overflow, underflow and rounding bugs in disclosed reports
Solidity 0.8 removed the easy overflows. Precision loss, unchecked blocks and casting errors kept the class alive.
- Reports indexed
- 54
- Total paid
- $180k
- Critical
- 0
- Largest payout
- $180k
Built-in overflow checks retired the classic `balance -= amount` underflow, and the class immediately reappeared in three new forms. Explicit `unchecked` blocks added for gas savings reintroduce the original bug with none of the original excuse. Downcasts from `uint256` to `uint128` or `uint64` silently truncate. And on non-EVM chains, Rust release builds wrap on overflow unless the arithmetic is explicitly checked.
The higher-value findings in this class are rounding rather than wrapping. Integer division truncates toward zero, and a protocol that rounds in the user's favour on deposit and again on withdrawal leaks value on every cycle. Share-price vaults are the classic target: the first depositor inflates the share price so that later deposits round down to zero shares.
These bugs are quiet. They rarely revert, they rarely trip monitoring, and they are usually found by writing the invariant down and testing it at the boundaries.
What reviewers look for
- `unchecked` blocks around arithmetic that depends on user input
- Downcasts to smaller integer widths without a bound check
- Division performed before multiplication in a fee or share calculation
- Empty-vault share price paths and first-depositor inflation
- Rust arithmetic without `checked_*` / `saturating_*` in release builds
Curated highlights
The largest disclosed payouts in this group, with our own summary of each. Every report links back to the original disclosure.
Unchecked arithmetic in Move coin split enables balance underflow
A custom coin-splitting helper in a Move-based decentralized exchange implemented unsafe u128 downcasting that bypassed native Move checked arithmetic. Combined with a stale balance check preceding an internal callback, an attacker could request a swap amount exceeding their actual balance. The resulting u128 subtraction underflow truncated upon downcasting into a valid u64 value, crediting the attacker with an artificially inflated balance that could subsequently be drained from the exchange.
Putty: Options with a small strike price will round down to 0 and can prevent assets to be withdrawn
The Putty protocol contains a vulnerability where certain ERC-20 tokens, which revert on zero-value transfers, can cause a Denial-of-Service during asset withdrawals. The issue occurs because the protocol's fee calculation uses integer division, which can round down to zero for small strike prices and low fee rates. When the contract attempts to transfer this zero-value fee to the protocol's treasury, the transaction reverts, permanently locking the user's assets within the vault.
PoolTogether: Loss of precision leads to under-collateralized
PoolTogether's vault implementation incorrectly triggers an under-collateralized state due to rounding errors during yield vault interactions. When checking the solvency of the underlying assets, the protocol treats a 1 wei discrepancy—common in standard share-based accounting—as a genuine loss of capital. This flaw bricked the deposit functionality for users, effectively forcing the vault into a permanent withdrawal-only state despite no actual asset loss.
Putty: Put options are free of any fees
The Putty protocol contains a logic error where put options bypass the required fee collection mechanism upon exercise. While call options correctly deduct a designated fee, the logic for put options transfers the full strike amount to the exerciser without any fee deduction. This failure results in consistent revenue leakage for the protocol, as put options are currently processed free of charge.
PoolTogether: Silent overflow could alter computation when calculating the `vaultPortion` in the `PrizePool` contract
The PrizePool contract in the PoolTogether V5 protocol contains an unsafe type conversion flaw that can lead to silent integer overflows. During the calculation of a vault's portion of prizes, contribution metrics returned as uint256 are cast to int256 without bound checks. If these contributions are sufficiently large, the overflow results in mathematically incorrect reward distribution, negatively impacting the prize yields for specific draws.
The Wildcat Protocol: User could withdraw more than supposed to, forcing last user withdraw to fail
In The Wildcat Protocol, withdrawal requests are batched and executed based on proportional interest scaling. When a market is closed, withdrawal requests within an active batch can be executed before all lenders have added their requests. A early withdrawer can execute at an outdated rate, while subsequent micro-withdrawals further alter precision and lower the batch rate, leaving insufficient unclaimed balance for remaining lenders. Consequently, the final user attempting to process their withdrawal experiences a transaction revert and permanent loss/locking of funds.
All reports in this group
- Superposition: Unintended under/overflow of the amount already swapped in/out due to unmatching logicInteger overflow/underflow$0
- Superposition: Missing `lower<upper` check in `mint_position`Integer overflow/underflow$0
- Superposition: `get_fee_growth_inside` in `tick.rs` should allow for `underflow`/`overflow` but doesn'tInteger overflow/underflow$0
- Superposition: Position's owed fees should allow underflow but it reverts instead, resulting in locked fundsInteger overflow/underflow$0
- BendDAO: `isolateRepay()` lack of check `onBehalf == nftOwner`Integer overflow/underflow$0
- Basin: Incorrectly assigned `decimal1` parameter upon decodingInteger overflow/underflow$0
- BendDAO: Revert due to underflow error, leading to lock of the liquidated NFTInteger overflow/underflow$0
- Basin: In `Stable2LUT1::getRatiosFromPriceLiquidity`, in extreme cases, `updateReserve` will start breakingInteger overflow/underflow$0
- BendDAO: Mismatch between yield amount deposited in shares calculation and `getAccountYieldBalance()`Integer overflow/underflow$0
- Munchables: in `farmPlots()` an underflow in edge case leading to freeze of funds (NFT)Integer overflow/underflow$0
- Optimism: Multiplication overflow leading to memory corruption and incorrect register write-backInteger overflow/underflow$0
- Munchables: Miscalculation in `_farmPlots` function could lead to a user unable to unstake all NFTsInteger overflow/underflow$0
- Olas: Incorrect handling of last nominee removal in `removeNominee` functionInteger overflow/underflow$0
- Olas: Non-normalized amounts sent via Wormhole lead to failure to redeem incentivesInteger overflow/underflow$0
- Thorchain: Incorrect call argument in `THORChain_Router::_transferOutAndCallV5`, leading to grief/steal of `THORChain_Aggregator`'s funds or DoSInteger overflow/underflow$0
- Panoptic: Overflow in `CollateralTracker` allows minting shares for freeInteger overflow/underflow$0
- Abracadabra Money: Permanent loss of yield for stakers in reward pools due to precision loss.Integer overflow/underflow$0
- Wise Lending: Wrong use of `nftID` to check if a `PowerFarm` position is an Aave positionInteger overflow/underflow$0
- Wise Lending: Precision loss in the calculation of the fee amounts and fee shares inside the `_preparePool` function of the `MainHelper` contractInteger overflow/underflow$0
- Abracadabra Money: Less base tokens are transferred when selling quote tokens due to the precision loss that occurred in `_GeneralIntegrate()`Integer overflow/underflow$0
- Salty.IO: Suboptimal arbitrage implementationInteger overflow/underflow$0
- Salty.IO: Incorrect assumption in PoolMath.sol can cause underflow when zapping is usedInteger overflow/underflow$0
- Salty.IO: The user who withdraws liquidity from a particular pool is able to claim more rewards than they should by carefully selecting a `decreaseShareAmount` value such that the `virtualRewardsToRemove` is rounded down to zeroInteger overflow/underflow$0
- PoolTogether: `PrizeVault.maxDeposit()` doesn't take into account produced feesInteger overflow/underflow$0
- PoolTogether: `maxDeposit()` uses `yieldVault.maxDeposit()` but `_depositAndMint()` uses `yieldVault.mint()`Integer overflow/underflow$0
- Ethereum Credit Guild: Over 90% of the Guild staked in a gauge can be unstaked, despite the gauge utilizing its full debt allocationInteger overflow/underflow$0
- Ethereum Credit Guild: `totalBorrowedCredit` can revert, breaking gauges.Integer overflow/underflow$0
- Ethereum Credit Guild: Rounding errors can cause ERC20RebaseDistributor transfers and mints to fail for underflowInteger overflow/underflow$0
- Collective: Malicious delegatees can block delegators from redelegating and from sending their NFTsInteger overflow/underflow$0
- Collective: ERC20TokenEmitter will not work after a certain period of timeInteger overflow/underflow$0
- Olas: Withdrawals can be frozen by creating null depositsInteger overflow/underflow$0
- NextGen: `getPrice` `salesOption` 2 can round down to the lower barrier, skipping the last time periodInteger overflow/underflow$0
- NextGen: Multiple mints can brick any form of `salesOption` 3 mintingsInteger overflow/underflow$0
- Open Dollar: Incorrect calculations for Surplus Auction creation cause massive surplus imbalancesInteger overflow/underflow$0
- Wildcat Protocol: Calculation for lender withdrawals in `_applyWithdrawalBatchPayment()` should not round upInteger overflow/underflow$0
- Tapioca DAO: Incorrect formula used in function `Market.computeClosingFactor()`Integer overflow/underflow$0
- Tapioca DAO: Overflow risk in Market contractInteger overflow/underflow$0
- Tapioca DAO: Incorrect solvency check because it multiplies collateralizationRate by share not amount when calculating liquidation thresholdInteger overflow/underflow$0
- Centrifuge: Investors claiming their `maxDeposit` by using the `LiquidityPool.deposit()` will cause other users to be unable to claim their `maxDeposit`/`maxMint`Integer overflow/underflow$0
- Maia DAO Ecosystem: Maia Governance token balance dilution in `vMaia` vault is breaking the conversion rate mechanismInteger overflow/underflow$0
- Maia DAO Ecosystem: DoS of `RootBridgeAgent` due to missing negation of return values for `UniswapV3Pool.swap()`Integer overflow/underflow$0
- Maia DAO Ecosystem: `UlyssesToken` asset ID accounting errorInteger overflow/underflow$0
- Maia DAO Ecosystem: Slippage controls for calling `bHermes` contract's `ERC4626DepositOnly.deposit` and `ERC4626DepositOnly.mint` functions are missingInteger overflow/underflow$0
- Maia DAO Ecosystem: `vMaia` Lacks of override in `forfeitBoost`Integer overflow/underflow$0
- Maia DAO Ecosystem: An attacker can exploit the "deposit" to drain the `Ulysess Liquidity Pool`Integer overflow/underflow$0
- Maia DAO Ecosystem: Second per liquidity inside could overflow `uint256` causing the LP position to be locked in `UniswapV3Staker`Integer overflow/underflow$0
- Lybra Finance: Liquidation won't work when bad and safe collateral ratio are set to default valuesInteger overflow/underflow$0
- Asymmetry Finance: An attacker can manipulate the preDepositvePrice to steal from other usersInteger overflow/underflow$0