Returnbomb Remediation
Overview
Related Detector: Returnbomb
A “return bomb” is a hostile callee that returns a huge byte array. When the caller automatically copies returndata into memory — which the high-level (bool ok, bytes memory ret) = target.call(...) form does — memory expansion gas grows quadratically and can exhaust the gas forwarded, forcing a revert. In relayers, multicall, and try/catch flows this lets one target grief the whole batch. The remediation is to not copy unbounded returndata from untrusted targets.
Recommended Fix
Before (Vulnerable)
function forward(address target, bytes calldata data) external {
// The callee can return megabytes; copying it can burn all forwarded gas.
(bool ok, bytes memory ret) = target.call(data);
require(ok, string(ret));
}
After (Fixed — ignore returndata, or cap the copy in assembly)
function forward(address target, bytes calldata data) external {
bool ok;
assembly {
// Copy zero bytes of returndata: success/failure is captured, the bomb is not.
ok := call(gas(), target, 0, add(data, 0x20), data.length, 0, 0)
}
require(ok, "Call failed");
}
When you must read a return value, copy only a bounded prefix (for example the first 32 bytes for a bool/uint256) with returndatacopy, rather than the full returndatasize().
Common Mistakes
- Using
try/catcharound an external call and letting the compiler-generated returndata copy absorb the bomb. - Copying
returndatasize()bytes to build a revert reason, which re-exposes the same unbounded copy. - Assuming a low gas stipend protects you; the quadratic memory cost can exceed even large gas budgets.