Token-0x

First Flight #54
Beginner FriendlyDeFi
100 EXP
View results
Submission Details
Severity: high
Valid

Arithemtic overflow in Mint function

Root + Impact

Description

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.

let accountBalanceSlot := keccak256(ptr, 0x40)
let accountBalance := sload(accountBalanceSlot)
//overflow
sstore(accountBalanceSlot, add(accountBalance, value))

Risk

Likelihood:

  • High

Impact:

  • An attacker could manipulate the total supply and individual balances by causing integer overflow. This would allow minting of virtually unlimited tokens, complete devaluation of the token, and potential theft of value from existing holders. The economic model of the token would be completely broken.

Proof of Concept

function test_overflow() public{
//minting the max in uint 256
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);
//Giving it one more than the max
token.mint(account, 1);
balance = token.balanceOf(account);
//It should be equal to zero now
assertEq(balance, 0);
assertEq(token.totalSupply(), 0);
}

Recommended Mitigation

- 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)
}
}
Updates

Lead Judging Commences

gaurangbrdv Lead Judge 20 days ago
Submission Judgement Published
Validated
Assigned finding tags:

overflow & underflow

missing checks for overflow and underflow.

Support

FAQs

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

Give us feedback!