Token-0x

First Flight #54
Beginner FriendlyDeFi
100 EXP
Submission Details
Impact: high
Likelihood: high

Missing Overflow/Underflow Checks in Yul Assembly Arithmetic Operations

Author Revealed upon completion

Root + Impact

Description

  • Normal behavior: ERC20 transfers/mints/burns must revert on overflow/underflow to keep balances and totalSupply correct.

  • Issue: Yul add/sub are unchecked, so balances and supply wrap instead of reverting.

// Root cause with @> marker
// File: src/helpers/ERC20Internals.sol (lines 92–131)
sstore(fromSlot, sub(fromAmount, value))
@> sstore(toSlot, add(toAmount, value)) // unchecked add wraps

Similar unchecked add in _mint (supply/balance) and unchecked sub in _burn.

Risk

Likelihood:

  • Large rewards/emissions or whale balances reach near 2^256-1; next add wraps.

  • Protocol mints near max supply; subsequent mint/transfer wraps silently.

Impact:

  • Balance corruption and fund loss for recipients.

  • totalSupply corruption breaks protocol/token economics.

Proof of Concept

function testOverflow() public {
// Vulnerable path: unchecked add in _transfer
token.transfer(victim, 200);
// (maxUint - 100 + 200) mod 2^256 = 99 due to unchecked add
console2.log("Victim balance after overflow transfer:", token.balanceOf(victim));
assertEq(token.balanceOf(victim), 99);
}

Why 99: max = 2^256 - 1; max - 100 + 200 = 2^256 + 99; mod 2^256 leaves 99.

Observed output (Forge):

Ran 1 test for test/OverflowPOC.t.sol:OverflowPOCTest
[PASS] testOverflow() (gas: 27925)
Logs:
Victim balance after overflow transfer: 99
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.80ms (4.05ms CPU time)

Recommended Mitigation

- sstore(toSlot, add(toAmount, value))
+ let newTo := add(toAmount, value)
+ if lt(newTo, toAmount) { revert(0, 0) } // overflow
+ sstore(toSlot, newTo)

Add equivalent overflow checks in _mint (supply and balance) and underflow checks in _burn before sstore.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!