Token-0x

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

Integer Overflow in `_transfer` for Recipient Balance

Author Revealed upon completion

Root + Impact

The _transfer function uses unchecked assembly arithmetic when adding to the recipient's balance, allowing silent integer overflow that can cause loss of tokens.

Description

  • While the _transfer function checks if the sender has sufficient balance, it does not check for overflow when adding to the recipient's balance.

  • In Yul assembly, the add operation wraps on overflow without reverting.

function _transfer(address from, address to, uint256 value) internal returns (bool success) {
assembly ("memory-safe") {
// ... validation and balance loading ...
if lt(fromAmount, value) {
// ... revert for insufficient balance ...
}
sstore(fromSlot, sub(fromAmount, value))
@> sstore(toSlot, add(toAmount, value)) // No overflow check!
// ...
}
}

Risk

Likelihood:

  • Requires recipient to already have a balance close to type(uint256).max

  • Unlikely in normal operation but possible in edge cases

Impact:

  • Recipient's balance wraps to a small value

  • Tokens are effectively lost/destroyed

  • Accounting inconsistency between totalSupply and sum of balances

Proof of Concept

function test_transferOverflow() public {
address richUser = makeAddr("rich");
address sender = makeAddr("sender");
// Rich user has near max tokens
token.mint(richUser, type(uint256).max - 100);
token.mint(sender, 200);
// Transfer causes overflow
vm.prank(sender);
token.transfer(richUser, 200);
// Rich user's balance overflowed
assertEq(token.balanceOf(richUser), 99); // Wrapped around!
}

Recommended Mitigation

Add overflow check before storing the new recipient balance.

function _transfer(address from, address to, uint256 value) internal returns (bool success) {
assembly ("memory-safe") {
// ... existing code ...
sstore(fromSlot, sub(fromAmount, value))
+ let newToAmount := add(toAmount, value)
+ // Check for overflow
+ if lt(newToAmount, toAmount) {
+ revert(0, 0)
+ }
- sstore(toSlot, add(toAmount, value))
+ sstore(toSlot, newToAmount)
// ...
}
}

Support

FAQs

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

Give us feedback!