Skip to main content

Call to Untrusted Contract

Why is this important?

There exists a special variant of a message call, named delegatecall which is identical to a message call apart from the fact that the code at the target address is executed in the context of the calling contract and msg.sender and msg.value do not change their values. This allows a smart contract to dynamically load code from a different address at runtime. Storage, current address and balance still refer to the calling contract.

Calling into untrusted contracts is very dangerous, as the code at the target address can change any storage values of the caller and has full control over the caller's balance.

Avoid Calls to untrusted Contracts

Option A: Ensure delegatecall is used securely

  1. Go through the issues that GuardRails identified in the PR/MR

  2. Identify the code that looks like this:

    pragma solidity ^0.4.24;

    contract Proxy {

    address owner;

    constructor() public {
    // This is the issue
    owner = msg.sender;
    }

    function forward(address callee, bytes _data) public {
    require(callee.delegatecall(_data));
    }
    }
  3. Check the target address against an allowlist of trusted contracts

    pragma solidity ^0.4.24;

    contract Proxy {

    address callee;
    address owner;

    modifier onlyOwner {
    require(msg.sender == owner);
    _;
    }

    constructor() public {
    callee = address(0x0);
    owner = msg.sender;
    }

    function setCallee(address newCallee) public onlyOwner {
    callee = newCallee;
    }

    function forward(bytes _data) public {
    require(callee.delegatecall(_data));
    }

    }
  4. Test it

  5. Ship it 🚢 and relax 🌴

More information: