Token-0x

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

Unchecked Balance Underflow in `_burn`

Author Revealed upon completion

Description

  • The _burn function is expected to decrease a user's balance and the total supply by a specified amount, reverting if the user has insufficient funds.

  • The function uses Unchecked Yul sub instructions without any prior comparison check; this causes the calculation to wrap around to type(uint256).max when trying to subtract a value larger than the balance.

/// File: src/helpers/ERC20Internals.sol:L177-L178
let accountBalance := sload(accountBalanceSlot)
@> sstore(accountBalanceSlot, sub(accountBalance, value)) // No check: 10 - 11 = MAX_UINT

Risk

Likelihood:

  • A user calls the public burn function with an amount greater than their current balance.

Impact:

  • The user gains a practically infinite balance (type(uint256).max), allowing them to dump tokens or dominate governance.

  • Token total supply becomes corrupted, destroying trust in the token.

Proof of Concept

function test_BurnUnderflow() public {
// 1. Setup
token.mint(alice, 10);
assertEq(token.balanceOf(alice), 10, "Alice should have 10 tokens");
// 2. Exploit steps
// Burn 11 tokens (1 more than balance).
// This should revert but will underflow instead.
token.burn(alice, 11);
// 3. Assertions (impact)
// 10 - 11 = -1 -> type(uint256).max due to unchecked sub
uint256 expectedBalance = type(uint256).max;
console.log("Alice Balance:", token.balanceOf(alice));
assertEq(token.balanceOf(alice), expectedBalance, "Alice balance did not underflow as expected (Vulnerability confirmed!)");
}

Recommended Mitigation

let accountBalance := sload(accountBalanceSlot)
+ if lt(accountBalance, value) { revert(0, 0) }
sstore(accountBalanceSlot, sub(accountBalance, value))

Support

FAQs

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

Give us feedback!