Skip to main content
Sigvex

Short Address Attack

Detects ERC-20 transfer functions vulnerable to short address attacks where truncated addresses cause the amount parameter to be left-shifted.

Short Address Attack

Overview

Remediation Guide: How to Fix Short Address Attack

The short address detector identifies ERC-20 token contracts that do not validate calldata length, making them vulnerable to the short address attack (SWC-130). When a caller sends fewer bytes than expected, the ABI decoder zero-pads the missing bytes on the right, effectively left-shifting the amount parameter. A 19-byte address (missing the last zero byte) causes the amount to be multiplied by 256.

Why This Is an Issue

The EVM ABI encoding packs parameters sequentially. For transfer(address,uint256):

  • Bytes 0-3: function selector
  • Bytes 4-35: address (20 bytes, left-padded to 32)
  • Bytes 36-67: amount (uint256, 32 bytes)

If the caller sends only 67 bytes instead of 68 (because the address ends in 0x00 and is truncated to 19 bytes), the EVM right-pads with zeros. The amount parameter effectively shifts left by 8 bits, multiplying it by 256.

Modern Solidity compilers (0.5.0+) include calldata length checks that prevent this attack. However, contracts compiled with older versions or using inline assembly for ABI decoding remain vulnerable.

How to Resolve

// Before: No calldata length validation (Solidity < 0.5.0)
function transfer(address to, uint256 amount) public returns (bool) {
    require(balances[msg.sender] >= amount);
    balances[msg.sender] -= amount;
    balances[to] += amount;
    return true;
}

// After: Explicit calldata length check
function transfer(address to, uint256 amount) public returns (bool) {
    require(msg.data.length >= 68, "Invalid calldata length"); // 4 + 32 + 32
    require(balances[msg.sender] >= amount);
    balances[msg.sender] -= amount;
    balances[to] += amount;
    return true;
}

Examples

Sample Sigvex Output

{
  "detector_id": "short-address",
  "severity": "high",
  "confidence": 0.72,
  "description": "ERC-20 transfer function lacks calldata length validation. A caller supplying a 19-byte address can shift the amount parameter by 8 bits, multiplying the transfer amount by 256.",
  "location": { "function": "transfer(address,uint256)", "offset": 0 }
}

Detection Methodology

  1. ERC-20 pattern matching: Identifies transfer/transferFrom functions by selector.
  2. Calldata validation scan: Checks for CALLDATASIZE comparison against expected minimum length.
  3. Compiler version inference: Lower confidence for contracts likely compiled with Solidity >= 0.5.0 (which includes automatic length checks).

Limitations

  • Modern Solidity (>= 0.5.0) includes built-in calldata length validation, making this largely a legacy issue. The detector still flags it for completeness when bytecode lacks the check.
  • Proxy contracts where calldata is forwarded via DELEGATECALL may mask the length check performed by the implementation.

References