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
Go through the issues that GuardRails identified in the PR/MR
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));
}
}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));
}
}Test it
Ship it 🚢 and relax 🌴