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
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
- ERC-20 pattern matching: Identifies transfer/transferFrom functions by selector.
- Calldata validation scan: Checks for
CALLDATASIZEcomparison against expected minimum length. - 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.
Related Detectors
- Input Validation — general missing input validation
- ERC-20 Violations — ERC-20 standard compliance issues