Ethernaut Lvl 4 Telephone Walkthrough: how to abuse tx.origin & msg.sender

This is a in-depth series around Zeppelin team’s smart contract security puzzles. I’ll give you the direct resources and key concepts you’ll need to solve the puzzles 100% on your own.

Nicole Zhu
2 min readAug 18, 2018

This levels requires you to learn the nuances between tx.origin vs msg.sender to claim ownership of the contract.


  • The original user wallet that initiated the transaction
  • The origin address of potentially an entire chain of transactions and calls
  • Only user wallet addresses can be the tx.origin
  • A contract address can never be the tx.origin


  • The immediate sender of this specific transaction or call
  • Both user wallets and smart contracts can be the msg.sender

Example scenarios:

Where tx.origin, msg.sender is observed in the context of the very last node:

Tip: msg.sender checks where the external function call directly came from. msg.sender is typically who you want to authenticate.

Detailed Walkthrough

  1. Notice Telephone.sol’s changeOwner function checks if (tx.origin != msg.sender). Seems like we can successfully trigger this function with scenario 3:

2. Create a phone contract, Telephony to pose as Contract A. Instantiate Contract B, your Telephone.sol, inside Telephony:

contract Telephony {    Telephone public phone = Telephone(YOUR_INSTANCE_ADDR_HERE);    //TODO...

3. Create a changeOwner function inside Telephony that calls the changeOwner function in Telephone, i.e. play the game of Telephone.

function changeOwner(address _owner) public {

4. Notice await contract.owner() in console now indicate your user wallet is the owner!