5

I couldn't find an appropriate, simple fix of the tx.origin vulnerability, without having to use any modifier, any help is very much appreciated,

thanks,

PS: msg.sender is not what I'm looking for (if another contract calls your contract msg.sender will be the address of the contract and not the address of the user who called the contract)

contract Proxy {

    address myAddress;

    function callMyContract() public view returns(address) {
        MyContract(myAddress).doSomthing();
    }
}

contract MyContract {

    event Something(address sender);

    function doSomthing() public (address) {
        emit Something(msg.sender); // Proxy address
        emit Something(tx.origin); // User address (the one I need) but vulnerable
    }
}

1 Answer 1

7

The vulnerabilities with tx.origin are from its semantics themselves, so there is no direct alternative. The common advice is to design your contract in a way that does not need tx.origin.

From: https://github.com/ethereum/solidity/issues/683:

  1. tx.origin is a security vulnerability. As we recently saw with the Mist wallet, using tx.origin makes you vulnerable to attacks comparable to phishing or cross-site scripting. Once a user has interacted with a malicious contract, that contract can then impersonate the user to any contract relying on tx.origin.

  2. tx.origin breaks compatibility. Using tx.origin means that your contract cannot be used by another contract, because a contract can never be the tx.origin. This breaks the general composability of Ethereum contracts, and makes them less useful. In addition, this is another security vulnerability, because it makes security-based contracts like multisig wallets incompatible with your contract.

  3. tx.origin is almost never useful. This is the most subjective point, but I have yet to come across a use of tx.origin that seemed legitimate to me. I welcome counter-examples, but I've written dozens or hundreds of smart contracts without needing it, and I have never heard of anyone else needing it either.

If you need tx.origin to check if a call is coming from a smart contract, you can use something like:

function isContract(address _addr) private returns (bool isContract){
  uint32 size;
  assembly {
    size := extcodesize(_addr)
  }
  return (size > 0);
}

Other Resources

6
  • Thanks for sharing @Mark, great stuff! Actually I'm working to prove the opposite: I'm using a proxy contract to interact with another contract and I need the original sender address, msg.sender does not help as it recovers the proxy address and not the user, Any suggestions on how to workaround? Thanks again for your help, I really appreciate it, cheers!
    – Arsalen
    Oct 24, 2019 at 23:02
  • Could you have the proxy contract pass its msg.sender along as a parameter for its delegatecall to the implementation contract?
    – Mark Toda
    Oct 24, 2019 at 23:08
  • I guess that would be the best approach, you think I have to use the onlyOwner modifier in order to prevent any malicious call? (otherwise anyone can mess with the parameter)
    – Arsalen
    Oct 24, 2019 at 23:19
  • 1
    Actually, if you are using delegatecall, you should not need to do that hack. Read ethereum.stackexchange.com/questions/3667/… -- when using delegatecall in a proxy, the original msg.sender is passed along to the implementation! Hopefully this solves your issue in a clean and safe way.
    – Mark Toda
    Oct 24, 2019 at 23:29
  • 1
    This contract (TrueUSD implementation) can also serve as an example for you as it uses a proxy / implementation pattern: etherscan.io/address/0xcb9a11afdc6bdb92e4a6235959455f28758b34ba
    – Mark Toda
    Oct 24, 2019 at 23:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.