Skip to main content
Sigvex

Unchecked Call Target Remediation

How to safely make low-level calls: validate the target, check the return value, and never delegatecall into attacker-controlled code.

Unchecked Call Target Remediation

Overview

Related Detector: Unchecked Call Target

A low-level call, delegatecall, or staticcall to an address the caller can influence is dangerous in two ways: the target may be a contract that behaves maliciously, and — with delegatecall — the target’s code runs in your storage context, so it can rewrite any state. The remediation is to constrain which targets are reachable and to handle the result explicitly.

Before (Vulnerable)

contract Router {
    function execute(address target, bytes calldata data) external {
        // Arbitrary delegatecall — target runs with this contract's storage and balance
        (bool ok, ) = target.delegatecall(data);
        require(ok);
    }
}

After (Fixed — allowlisted target, checked result, no arbitrary delegatecall)

contract Router {
    mapping(address => bool) public allowedTarget;

    error TargetNotAllowed();
    error EmptyTarget();

    function execute(address target, bytes calldata data) external returns (bytes memory) {
        if (!allowedTarget[target]) revert TargetNotAllowed();
        if (target.code.length == 0) revert EmptyTarget();   // reject EOAs / self-destructed code
        (bool ok, bytes memory ret) = target.call(data);     // call, not delegatecall
        require(ok, "Call failed");
        return ret;
    }
}

Prefer a fixed, immutable target or a small owner-managed allowlist. Reserve delegatecall for trusted, audited implementations (e.g. a proxy pointing at a known logic contract), never a caller-supplied address.

Common Mistakes

  • Checking ok but ignoring that a call to an address with no code returns true — validate code.length when the target must be a contract.
  • Allowlisting the target but still forwarding attacker-controlled data into a delegatecall, which can call privileged functions on the current contract.
  • Treating staticcall as safe input validation; it prevents state changes but not a hostile return value.

References