Token-0x

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

Integer Overflow in _mint() Allows Infinite Token Creation and Breaks Protocol Accounting

Author Revealed upon completion

Description

The _mint() function uses assembly code that bypasses Solidity 0.8+'s overflow protection. When totalSupply + value exceeds type(uint256).max, it wraps to a small number instead of reverting.

function _mint(address account, uint256 value) internal {
assembly ("memory-safe") {
let supply := sload(supplySlot)
sstore(supplySlot, add(supply, value)) // @> No overflow check
let accountBalance := sload(accountBalanceSlot)
sstore(accountBalanceSlot, add(accountBalance, value)) // @> No overflow check
}
}

Impact

  • totalSupply wraps to a small number while balances remain large

  • Breaks invariant: sum(balances) == totalSupply

  • Enables infinite minting once supply resets

  • Breaks DEX/protocol integrations relying on totalSupply()

Proof of Concept

Add the test to Token.t.sol:

function test_mintOverflow() public {
address user1 = makeAddr("user1");
address user2 = makeAddr("user2");
// Mint near max
token.mint(user1, type(uint256).max - 100);
// Mint more - causes overflow
token.mint(user2, 200);
// totalSupply wrapped to 99 instead of reverting
assertEq(token.totalSupply(), 99);
assert(token.balanceOf(user1) > token.totalSupply()); // Broken invariant
}

Run: forge test --mt test_mintOverflow -vv

Output shows totalSupply = 99 while user1 has massive balance.

Recommended Mitigation

Use regular Solidity instead of assembly:

function _mint(address account, uint256 value) internal {
+ require(account != address(0));
+ _totalSupply += value; // Reverts on overflow
+ _balances[account] += value;
- assembly { ... }
}

Or add a max supply cap:

require(_totalSupply + value <= MAX_SUPPLY);

Support

FAQs

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

Give us feedback!