Token-0x

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

Zero-Address Balance Query Revert Vulnerability

Author Revealed upon completion

Zero-Address Balance Query Revert Vulnerability

Description

  • A standard balanceOf function should allow querying the balance of any valid address, including the zero address (address(0)). This is a common practice in ERC20 standards, where the zero address typically represents burned or unallocated tokens.

  • The function immediately reverts when the input address is the zero address, causing external calls to token.balanceOf(address(0)) to fail. This violates the expected behavior of the standard ERC20 interface and may impact on-chain applications or monitoring tools that rely on querying the zero address balance.

function _balanceOf(address owner) internal view returns (uint256) {
assembly {
if iszero(owner) {
@> revert(0, 0)
}
let baseSlot := _balances.slot
let ptr := mload(0x40)
mstore(ptr, owner)
mstore(add(ptr, 0x20), baseSlot)
let dataSlot := keccak256(ptr, 0x40)
let amount := sload(dataSlot)
mstore(ptr, amount)
mstore(add(ptr, 0x20), 0)
return(ptr, 0x20)
}
}

Risk

Likelihood:

  • Any external contract or user attempting to query the zero address balance (e.g., for common operations such as calculating total circulating supply or burned token amount) will trigger a revert.

  • Frontend applications, blockchain explorers, or monitoring services will encounter transaction failures when attempting to read the zero address balance by default.

Impact:

  • Breaks compatibility with the ERC20 standard, leading to unexpected errors in third-party integrations that rely on standard behavior (e.g., wallets, exchanges, DeFi protocols).

  • Impedes transparent tracking of token economic data. For example, it becomes impossible to obtain the amount of burned tokens held by the zero address through a simple call, affecting the visibility of the token economic model.

Proof of Concept

  • Add the function test_1_balanceOf_AddressZero in Token.t.sol as follows:

function test_1_balanceOf_AddressZero() public {
vm.expectRevert();
uint256 balanceOfAddress0 = token.balanceOf(address(0));
}
  • Execute the command: forge test --mt test_1_balanceOf_AddressZero -vvvv

Ran 1 test for test/Token.t.sol:TokenTest
[PASS] test_1_balanceOf_AddressZero() (gas: 8933)
Traces:
[8933] TokenTest::test_1_balanceOf_AddressZero()
├─ [0] VM::expectRevert(custom error 0xf4844814)
│ └─ ← [Return]
├─ [502] Token::balanceOf(0x0000000000000000000000000000000000000000) [staticcall]
│ └─ ← [Revert] EvmError: Revert
└─ ← [Stop]
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 695.40µs (111.00µs CPU time)

Recommended Mitigation

function _balanceOf(address owner) internal view returns (uint256) {
assembly {
if iszero(owner) {
- revert(0, 0)
+ balance := 0
+ leave // Exit the assembly block and return balance=0
}
let baseSlot := _balances.slot
let ptr := mload(0x40)
mstore(ptr, owner)
mstore(add(ptr, 0x20), baseSlot)
let dataSlot := keccak256(ptr, 0x40)
let amount := sload(dataSlot)
mstore(ptr, amount)
mstore(add(ptr, 0x20), 0)
return(ptr, 0x20)
}
}

Support

FAQs

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

Give us feedback!