Integer Overflow
Detects arithmetic operations that may overflow or underflow, producing incorrect values that can lead to fund theft or unexpected behavior.
Integer Overflow
Overview
Remediation Guide: How to Fix Integer Overflow
The integer overflow detector identifies arithmetic operations — addition, subtraction, multiplication, and exponentiation — that are not protected against overflow or underflow at the bytecode level. In Solidity versions prior to 0.8.0, all arithmetic uses unchecked 256-bit integers by default. An addition that wraps around from 2^256 - 1 to 0, or a subtraction that wraps from 0 to 2^256 - 1, can corrupt balances, counters, and access control variables.
Sigvex analyzes the decompiled HIR for ADD, SUB, MUL, and EXP opcodes that are not preceded by SafeMath calls, Solidity 0.8+ overflow checks (which generate JUMPI guards), or explicit bounds checks. The detector also identifies the unchecked { } block pattern in Solidity 0.8+, which explicitly opts out of protection and is flagged when used with user-controlled inputs.
Why This Is an Issue
Integer arithmetic errors have historically caused severe financial losses. The BEC token hack (April 2018) exploited a multiplication overflow in the batchTransfer function to mint an enormous quantity of tokens from nothing. The SMT token suffered the same class of bug days later. These attacks transferred billions of dollars in nominal token value by manufacturing tokens via arithmetic wrap-around.
Even in Solidity 0.8+, the unchecked block disables protection. Production DeFi code often uses unchecked for gas optimization inside loops, and developers sometimes inadvertently include user-supplied values in unchecked arithmetic.
How to Resolve
// Before: Vulnerable (Solidity < 0.8.0, no SafeMath)
function transfer(address to, uint256 amount) external {
balances[msg.sender] -= amount; // Can underflow if amount > balance
balances[to] += amount; // Can overflow if to's balance is near max
}
// After: Use Solidity >= 0.8.0 (automatic checks)
// pragma solidity ^0.8.0; — all arithmetic is checked by default
function transfer(address to, uint256 amount) external {
// Reverts automatically if underflow or overflow occurs
balances[msg.sender] -= amount;
balances[to] += amount;
}
For legacy Solidity or deliberate unchecked usage:
// After: Explicit bounds check before unchecked arithmetic
function addReward(uint256 reward) external {
require(totalRewards + reward >= totalRewards, "Overflow"); // Check first
unchecked {
totalRewards += reward; // Safe — checked above
}
}
Examples
Vulnerable Code
// Solidity 0.7.x — no built-in overflow protection
pragma solidity ^0.7.0;
contract VulnerableToken {
mapping(address => uint256) public balances;
// Multiplication can overflow for large inputs
function batchMint(address[] memory recipients, uint256 amountEach) external onlyOwner {
uint256 totalMinted = recipients.length * amountEach; // OVERFLOW if large values
totalSupply += totalMinted;
for (uint i = 0; i < recipients.length; i++) {
balances[recipients[i]] += amountEach;
}
}
}
Fixed Code
// Solidity 0.8.x — automatic overflow protection
pragma solidity ^0.8.0;
contract SafeToken {
mapping(address => uint256) public balances;
uint256 public totalSupply;
// All arithmetic in 0.8+ reverts on overflow/underflow
function batchMint(address[] memory recipients, uint256 amountEach) external onlyOwner {
uint256 totalMinted = recipients.length * amountEach; // Reverts if overflow
totalSupply += totalMinted;
for (uint i = 0; i < recipients.length; i++) {
balances[recipients[i]] += amountEach;
}
}
}
Sample Sigvex Output
{
"detector_id": "integer-overflow",
"severity": "high",
"confidence": 0.78,
"description": "MUL operation at offset 0x42 in function batchMint() operates on user-controlled input without overflow protection. Compiler version 0.7.6 detected.",
"location": { "function": "batchMint(address[],uint256)", "offset": 66 }
}
Detection Methodology
- Compiler version detection: The detector first checks whether the contract was compiled with Solidity 0.8+ by looking for characteristic overflow guard patterns in the bytecode prologue. Contracts compiled with 0.8+ receive lower base confidence.
- Arithmetic opcode scanning: It identifies
ADD,SUB,MUL, andEXPopcodes in function bodies. - SafeMath call detection: Checks whether arithmetic operations are wrapped in the SafeMath pattern (a
JUMPto a checked-arithmetic helper function recognized by its signature). - User-input taint tracking: Follows data-flow from
CALLDATALOADthrough arithmetic to determine whether user-controlled values reach unprotected operations. - Unchecked block detection: In Solidity 0.8+ bytecode, identifies arithmetic within
unchecked { }regions (which produce no overflow guards) and flags those separately.
Limitations
False positives:
- Arithmetic on values that are logically bounded (e.g.,
block.timestamp, loop counters with enforced limits) may be flagged even though overflow is impossible in practice. - SafeMath inline expansions in Solidity < 0.8 may not always be recognized, leading to false positives on protected arithmetic.
False negatives:
- Division and modulo operations are not flagged by this detector (division by zero is covered by the
division-by-zerodetector). - Overflow through indirect paths (e.g., an intermediate result stored to memory then loaded) may be missed.
Related Detectors
- Unchecked Subtraction — specifically targets underflow from subtraction
- Precision Errors — detects division-before-multiplication and rounding errors