DEV Community

Cover image for Avoiding Security Vulnerabilities: The tx.origin vs msg.sender Debate
Chidozie Zeno Ezeanekwe
Chidozie Zeno Ezeanekwe

Posted on • Updated on

Avoiding Security Vulnerabilities: The tx.origin vs msg.sender Debate

In the world of Ethereum, it is crucial to understand the difference between tx.origin and msg.sender.
These two variables are often used to determine the identity of the sender of a transaction, but they have different use cases and can lead to different security risks if used incorrectly. In this post, we will explore the differences between tx.origin and msg.sender, and show code examples of how an attacker can take advantage of the wrong use of tx.origin.
We will also provide code examples to show the best ways to use tx.origin and msg.sender.

What is tx.origin?

tx.origin is a variable that represents the original sender of a transaction. It is the address of the account that originally created the transaction and sent it to the network. This variable is useful when creating smart contracts that need to verify the authenticity of a transaction, such as when implementing a multisig wallet

function isValidTransaction(address _sender) public view returns (bool) {
    return _sender == tx.origin;
}
Enter fullscreen mode Exit fullscreen mode

In the example above, the function isValidTransaction takes an address as an input and compares it to the tx.origin. If the two match, the function returns true, indicating that the transaction is valid.

What is msg.sender?

msg.sender is a variable that represents the current sender of a message or transaction. It is the address of the account that sent the current message or transaction to the smart contract. This variable is useful when creating smart contracts that need to determine the current sender of a message, such as when implementing an access control system.

function isAuthorized(address _sender) public view returns (bool) {
    return _sender == msg.sender;
}
Enter fullscreen mode Exit fullscreen mode

In the example above, the function isAuthorized takes an address as an input and compares it to the msg.sender. If the two match, the function returns true, indicating that the sender is authorized.

The security disadvantage of using tx.origin the wrong way

While tx.origin is useful for verifying the authenticity of a transaction, it can also be a security risk if used incorrectly. One common mistake is to use tx.origin instead of msg.sender when implementing an access control system.

// victim's contract
function transferEther() public {
    require(msg.sender == tx.origin, "Unauthorized access");
    // transfer ether code
}

Enter fullscreen mode Exit fullscreen mode

In the example above, the function transferEther uses tx.origin to check if the sender is authorized to perform the transfer. However, this is incorrect because tx.origin **represents the original sender of the transaction, not the current sender. An attacker can take advantage of this by creating a malicious contract that calls the **transferEther function on behalf of the original sender.

contract Attacker {
    function attack() public {
        address victim = address(this);
        victim.call(bytes4(keccak256("transferEther()")));
    }
}

Enter fullscreen mode Exit fullscreen mode

In the example above, the Attacker contract creates a transaction to call the transferEther function on the victim contract. Since the tx.origin is the address of the Attacker contract and not the original sender, the require **statement in the **transferEther function(in the victim's contract) will pass and the attacker will be able to successfully transfer ether from the victim contract.

This highlights the importance of using msg.sender instead of tx.origin when implementing an access control system. msg.sender represents the current sender of the message or transaction, and ensures that the correct account is being checked for authorization.

function transferEther() public {
    require(msg.sender == authorizedAccount, "Unauthorized access");
    // transfer ether code
}
Enter fullscreen mode Exit fullscreen mode

In the example above, the function transferEther uses msg.sender to check if the sender is authorized to perform the transfer. This ensures that only the authorized account can transfer ether from the contract, and prevents malicious contracts from bypassing the access control system.

So when to use tx.origin? 🤔

tx.origin should be used when the smart contract needs to verify the authenticity of a transaction. This includes cases such as multisig wallets or contracts that need to ensure that a transaction was created by a specific address.

function confirmTransaction(bytes32 _hash) public {
    require(tx.origin == multisigWallet, "Invalid confirmation");
    // confirm transaction code
}

Enter fullscreen mode Exit fullscreen mode

In the example above, the function confirmTransaction uses tx.origin to ensure that the confirmation is coming from the correct multisig wallet. This prevents malicious contracts from confirming transactions on behalf of the multisig wallet.

And when do we use msg.sender?

msg.sender should be used when the smart contract needs to determine the current sender of a message or transaction. This includes cases such as access control systems or contracts that need to track the actions of a specific address.

function addAdmin(address _newAdmin) public {
    require(msg.sender == owner, "Unauthorized access");
    admins[_newAdmin] = true;
}
Enter fullscreen mode Exit fullscreen mode

In the example above, the function addAdmin **uses **msg.sender to ensure that the request to add a new admin is coming from the contract owner. This prevents malicious contracts from adding new admins on behalf of the contract owner.

In conclusion,

it is important to understand the difference between tx.origin and msg.sender, as well as when and how to use them correctly. Using tx.origin incorrectly in an access control system can lead to security vulnerabilities, while using msg.sender correctly can help to secure the contract. Always be cautious and double check your code when using these variables.

Also, Kindly connect with me on linkedin and follow me on Twitter, I follow back.

Top comments (2)

Collapse
 
priteshusadadiya profile image
Pritesh Usadadiya

[[..Pingback..]]
This article was curated as a part of #73rd Issue of Software Testing Notes Newsletter.

Collapse
 
zenodavids profile image
Chidozie Zeno Ezeanekwe

Thank you so much for letting me know that my article was curated in someone else's blog post. I really appreciate your support and kindness in bringing this to my attention. Your notification has made my day and I am thrilled to know that my work is being recognized. Thank you again for your time and effort in spreading the word about my article.