Skip to main content
Sigvex

Remediating Arbitrary External Calls

How to prevent external calls to user-controlled addresses by validating targets against whitelists.

Remediating Arbitrary External Calls

Overview

Related Detector: Arbitrary External Calls

External calls to user-supplied addresses must be validated before execution. The recommended approach depends on whether the set of valid targets is known at deployment or changes over time.

Before (Vulnerable)

function relay(address target, bytes calldata data) external {
    (bool success, ) = target.call(data);
    require(success);
}

After (Fixed)

address public immutable trustedTarget;

constructor(address _target) {
    trustedTarget = _target;
}

function relay(bytes calldata data) external {
    (bool success, ) = trustedTarget.call(data);
    require(success);
}

Alternative Mitigations

  • Whitelist mapping: For multiple valid targets, use mapping(address => bool) public approved with admin-only setter.
  • Interface validation: Call ERC165.supportsInterface() on the target before executing. This does not prevent malicious contracts but confirms the target implements the expected interface.
  • Immutable addresses: Use immutable for addresses that should not change after deployment.

Common Mistakes

  • Checking code size only: require(target.code.length > 0) prevents calls to EOAs but does not prevent calls to malicious contracts.
  • Post-call validation: Checking return data after the call does not prevent the external code from executing side effects during the call.

References