The _mint function performs unchecked addition operations in assembly without overflow protection. When minting tokens, both the total supply and account balance are increased using the 'add' opcode without any overflow checks. In Solidity 0.8+, automatic overflow protection only applies to Solidity code, not inline assembly. An attacker who gains access to the mint function could mint MAX_UINT256 tokens, causing the total supply and balance to overflow back to a small number, effectively resetting the token supply and allowing infinite minting.
function test_overflow() public{
uint256 amount = type(uint256).max;
address account = makeAddr("account");
token.mint(account, amount);
uint256 balance = token.balanceOf(account);
assertEq(balance, amount);
assertEq(token.totalSupply(), amount);
token.mint(account, 1);
balance = token.balanceOf(account);
assertEq(balance, 0);
assertEq(token.totalSupply(), 0);
}
- remove this code
function _mint(address account, uint256 value) internal {
assembly ("memory-safe") {
if iszero(account) {
mstore(0x00, shl(224, 0xec442f05))
mstore(add(0x00, 4), 0x00)
revert(0x00, 0x24)
}
let ptr := mload(0x40)
let balanceSlot := _balances.slot
let supplySlot := _totalSupply.slot
let supply := sload(supplySlot)
sstore(supplySlot, add(supply, value))
mstore(ptr, account)
mstore(add(ptr, 0x20), balanceSlot)
let accountBalanceSlot := keccak256(ptr, 0x40)
let accountBalance := sload(accountBalanceSlot)
//overflow
sstore(accountBalanceSlot, add(accountBalance, value))
}
}
+ add this code
function _mint(address account, uint256 value) internal {
assembly ("memory-safe") {
if iszero(account) {
mstore(0x00, shl(224, 0xec442f05))
mstore(add(0x00, 4), 0x00)
revert(0x00, 0x24)
}
let ptr := mload(0x40)
let balanceSlot := _balances.slot
let supplySlot := _totalSupply.slot
let supply := sload(supplySlot)
let newSupply := add(supply, value)
// Check for overflow
if lt(newSupply, supply) {
revert(0, 0)
}
sstore(supplySlot, newSupply)
mstore(ptr, account)
mstore(add(ptr, 0x20), balanceSlot)
let accountBalanceSlot := keccak256(ptr, 0x40)
let accountBalance := sload(accountBalanceSlot)
let newBalance := add(accountBalance, value)
// Check for overflow
if lt(newBalance, accountBalance) {
revert(0, 0)
}
sstore(accountBalanceSlot, newBalance)
}
}