Short Address Attack Remediation
Overview
The ABI encoder zero-pads missing calldata bytes on the right. If a caller submits a 19-byte address (dropping a trailing 0x00), the decoder shifts the following amount parameter left by 8 bits, multiplying the transfer by 256. The fix is to verify that calldata is at least as long as the encoded parameters before acting on the decoded values.
Related Detector: Short Address Attack
Recommended Fix
Before (Vulnerable)
function transfer(address to, uint256 amount) public returns (bool) {
require(balances[msg.sender] >= amount);
balances[msg.sender] -= amount;
balances[to] += amount;
return true;
}
After (Fixed)
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;
}
The length check (4 selector bytes plus two 32-byte words) rejects any call where the encoder would have padded a truncated argument, so the decoded amount can never be silently scaled by missing bytes.
Alternative Mitigations
- Compile with a recent Solidity release. Versions since 0.5.0 emit automatic calldata-length validation, which removes this attack for normally compiled contracts. Upgrading is the most durable fix.
- Validate inputs at the user-facing boundary (wallet, frontend, relayer) so malformed addresses never reach the contract — though on-chain validation must remain the authoritative line of defense.
- Avoid hand-rolled inline-assembly ABI decoding, which is where modern contracts most often reintroduce this gap.
Common Mistakes
- Adding the length check only to
transferwhile leavingtransferFrom,approve, and other multi-argument functions unguarded. - Using a strict
==comparison onmsg.data.length, which breaks legitimate callers that append extra data (for example, ERC-2771 meta-transaction suffixes). Use>=against the minimum. - Assuming a modern compiler protects forwarded calls in a proxy; calldata relayed via
DELEGATECALLmay bypass checks the implementation expects.