Token-0x

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

Missing Underflow Protection in Internal Burn Enables Supply and Balance Corruption

Author Revealed upon completion

[H-03] Missing Underflow Protection in Internal Burn Enables Supply and Balance Corruption

Description

The ERC20 core implementation contains a critical arithmetic safety flaw in the token burning logic.
The _burn() function inside ERC20Internals.sol performs raw subtraction inside inline assembly without any underflow protection.

If the burn amount exceeds the current user balance or total token supply, the subtraction wraps around due to unchecked EVM arithmetic, producing extremely large values. This permanently corrupts both the global supply accounting and individual balances.

Although _burn() is marked as internal, the contract is explicitly designed to be inherited. Any child contract can expose this functionality through a public or external wrapper, unintentionally or maliciously.

This creates a condition where attackers can inflate balances and destroy supply invariants by exploiting arithmetic wraparound.

// src/helpers/ERC20Internals.sol
function _burn(address account, uint256 value) internal {
assembly ("memory-safe") {
if iszero(account) {
mstore(0x00, shl(224, 0x96c6fd1e))
mstore(add(0x00, 4), 0x00)
revert(0x00, 0x24)
}
let supplySlot := _totalSupply.slot
let balanceSlot := _balances.slot
// @audit No underflow protection here.
let supply := sload(supplySlot)
sstore(supplySlot, sub(supply, value))
// @audit No underflow protection here.
let accountBalance := sload(accountBalanceSlot)
sstore(accountBalanceSlot, sub(accountBalance, value))
}
}

Risk

Likelihood: High

  • The contract is designed for inheritance.

  • Assembly arithmetic bypasses Solidity 0.8+ safety checks.

  • No balance or supply validation exists.

Impact: Critical

  • Total supply corruption via underflow.

  • User balance inflation through arithmetic wraparound.

  • Broken token economics and permanent protocol integrity loss.

Proof of Concept

  • The following PoC demonstrates that burning more tokens than available causes underflow and corrupts both balance and total supply.

function test_PoC_BurnUnderflow() public {
address attacker = makeAddr("attacker");
token.mint(attacker, 1 ether);
// Burn more than attacker owns
token.burn(attacker, 2 ether);
uint256 attackerBalance = token.balanceOf(attacker);
uint256 supplyAfter = token.totalSupply();
assertGt(attackerBalance, type(uint256).max / 2);
assertGt(supplyAfter, type(uint256).max / 2);
}
forge test --match-test test_PoC_BurnUnderflow -vvv
  • The test passes, confirming that unchecked subtraction causes state corruption.

Recommended Mitigation

  • Add explicit underflow protection before subtraction.

function _burn(address account, uint256 value) internal {
+ if (balanceOf(account) < value) revert("Insufficient balance");
+ if (totalSupply < value) revert("Insufficient supply");
let supply := sload(supplySlot)
sstore(supplySlot, sub(supply, value))
let accountBalance := sload(accountBalanceSlot)
sstore(accountBalanceSlot, sub(accountBalance, value))
}

Support

FAQs

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

Give us feedback!