Unsafe Callback
Detects external callback hooks that execute untrusted code without proper validation, gas limits, or reentrancy protection.
Unsafe Callback
Overview
The unsafe callback detector identifies contracts that invoke external callback functions (hooks, notifiers, or user-provided function pointers) without adequate safeguards. Callbacks to untrusted addresses allow the callee to re-enter the calling contract, consume excessive gas, revert strategically, or manipulate state between operations. This differs from standard reentrancy in that the callback is an intentional design feature that lacks proper guardrails.
Why This Is an Issue
Many protocols use callback patterns for flash loans (onFlashLoan), token hooks (tokensReceived), and composability (onERC721Received). When these callbacks target user-controlled addresses, the callee can execute arbitrary logic. Without reentrancy guards, gas limits, or state finalization before the callback, the calling contract is vulnerable to state manipulation during the callback window.
How to Resolve
// Before: Vulnerable — callback with pending state changes
function flashLoan(address receiver, uint256 amount) external {
uint256 balBefore = token.balanceOf(address(this));
token.transfer(receiver, amount);
IFlashBorrower(receiver).onFlashLoan(msg.sender, amount); // Callback
// State check after callback — vulnerable to manipulation during callback
require(token.balanceOf(address(this)) >= balBefore + fee, "Repay failed");
}
// After: Fixed — reentrancy guard + gas limit
function flashLoan(address receiver, uint256 amount) external nonReentrant {
uint256 balBefore = token.balanceOf(address(this));
token.transfer(receiver, amount);
IFlashBorrower(receiver).onFlashLoan{gas: 100000}(msg.sender, amount);
require(token.balanceOf(address(this)) >= balBefore + fee, "Repay failed");
}
Detection Methodology
- Callback pattern detection: Identifies external calls where the target address comes from a function parameter or is user-controlled.
- State mutation analysis: Checks whether contract state is modified before the callback and read after it — the classic check-effect-interaction violation.
- Reentrancy guard check: Verifies whether a reentrancy guard (mutex) is active during the callback.
- Gas limit check: Flags callbacks that do not specify a gas limit, allowing the callee to consume all available gas.
Limitations
False positives: Callbacks to trusted, immutable contract addresses (e.g., known protocol addresses) are safe but may be flagged. False negatives: Callback patterns that use indirect dispatch (function selectors stored in mappings) may not be recognized as callbacks.
Related Detectors
- Reentrancy — detects standard reentrancy via external calls
- Token Hook Reentrancy — detects ERC-777/ERC-1155 hook reentrancy
- Returnbomb — detects return-data-based gas attacks