Skip to content
Last updated: September 03, 2025

SCWE-091: Lack of Zero Value Check in Token Transfers

Stable Version v0.0.1

This content is in the version-(v0.0.1) and still under active development, so it is subject to change any time (e.g. structure, IDs, content, URLs, etc.).

Send Feedback

Relationships

  • CWE-754: Improper Check for Unusual or Exceptional Conditions
    CWE-754 Link

Description

This weakness occurs when smart contracts perform ERC20 token transfers without first validating that the transfer amount is greater than zero. While most ERC20 tokens allow zero‑value transfers, some implementations (e.g., LEND and others) revert when the amount is zero. This inconsistency can cause unexpected reverts in production, disrupt execution flow, and prevent critical contract logic from completing successfully.
Common risks include:
- Unexpected revert when interacting with non‑standard ERC20 tokens that disallow zero‑value operations.
- Potential denial‑of‑service conditions if an attacker or integration repeatedly triggers zero‑value transfers.
- Broken integrations when protocols assume uniform ERC20 behavior across diverse tokens.

Remediation

  • Validate transfer amounts: Ensure amount > 0 before calling transfer/transferFrom.
  • Treat zero as a no‑op if acceptable: Early‑return when amount == 0 rather than calling token methods.
  • Use robust token wrappers: Centralize token operations (e.g., via OpenZeppelin SafeERC20) and standardize zero‑value handling.
  • Integration testing: Include zero‑value cases for all integrated tokens (especially known non‑standard tokens like LEND).
  • Input sanitization: Validate and sanitize externally supplied amounts prior to token interactions.

Examples

  • Vulnerable Code (No Zero Value Check)

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.7.0;
    
    import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
    
    contract ExampleContract {
        using SafeERC20 for IERC20;
        IERC20 public inToken;
        address public vault;
    
        function transferTokens(uint256 feeTokenAmount) external {
            // No validation → may revert with some ERC20 tokens
            inToken.safeTransfer(vault, feeTokenAmount);
        }
    }
    

  • Safe Code (With Zero Value Check)

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.7.0;
    
    import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
    
    contract ExampleContract {
        using SafeERC20 for IERC20;
        IERC20 public inToken;
        address public vault;
    
        function transferTokens(uint256 feeTokenAmount) external {
            require(feeTokenAmount > 0, "Amount must be greater than zero");
            inToken.safeTransfer(vault, feeTokenAmount);
        }
    }
    

  • Alternative Safe Pattern (No‑op on Zero)

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.7.0;
    
    import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
    
    contract ExampleContract {
        using SafeERC20 for IERC20;
        IERC20 public inToken;
        address public vault;
    
        function transferTokens(uint256 feeTokenAmount) external {
            if (feeTokenAmount == 0) {
                return; // Skip calling token methods to avoid non-standard reverts
            }
            inToken.safeTransfer(vault, feeTokenAmount);
        }
    }