Expanding on tx.origin vs. msg.sender
Both variables identify an address, but they refer to different actors in a transaction chain.
-
msg.sender: The immediate account that called the current function. It can be a user’s wallet or another smart contract. -
tx.origin: The original wallet account (Externally Owned Account) that started the entire chain of transactions. This value never changes, even through multiple contract-to-contract calls.
Using tx.origin for authorisation is extremely dangerous. Here is a classic phishing attack scenario:
-
The Victim Contract: You have a
MyWalletcontract with a function liketransferAllFunds(address target). For security, you add the checkrequire(tx.origin == owner);thinking only you can authorise transfers. -
The Attacker’s Contract: An attacker deploys a malicious contract, let’s call it
FreeKittensGame. -
The Trap: The attacker convinces you to interact with their
FreeKittensGameby calling one of its functions (e.g.,getFreeKitten()). -
The Exploit: Hidden inside the
getFreeKitten()function is a call to yourMyWallet.transferAllFunds()function, with the attacker’s address as the target.
When your wallet’s function runs:
-
The
msg.senderis theFreeKittensGamecontract’s address. A check againstownerwould fail here. -
The
tx.originis your wallet address, because you are the one who started this entire chain of calls. The checkrequire(tx.origin == owner);passes, and the attacker’s contract successfully drains your funds.
Rule of Thumb: Always use msg.sender for authorisation checks.