Unsafe tx.origin Usage
id: LS16H
title: Unsafe tx.origin Usage
baseSeverity: H
category: access-control
language: solidity
blockchain: [ethereum]
impact: Attacker can trick users into authorizing transactions that compromise their assets
status: draft
complexity: medium
attack_vector: phishing
mitigation_difficulty: easy
versions: [">=0.4.0", "<latest"]
cwe: CWE-640
swc: SWC-115
π Description
- Unsafe usage of
tx.originfor authentication or permission checks allows attackers to exploit phishing-style proxy contracts that forward transactions from unsuspecting users. - Unlike
msg.sender, which refers to the immediate caller,tx.originrefers to the original external account that initiated the transaction β even across multiple contract calls. - When
tx.originis used to restrict access (e.g.,require(tx.origin == owner)), a malicious contract can: - Call the vulnerable contract via a proxy,
- Bypass
msg.senderprotections, - And exploit user trust to drain funds or escalate privileges.
π¨ Vulnerable Code
contract UnsafeAuth {
address public owner;
constructor() {
owner = msg.sender;
}
function withdraw() external {
require(tx.origin == owner, "Not owner"); // β vulnerable
payable(msg.sender).transfer(address(this).balance);
}
}
π§ͺ Exploit Scenario
Step-by-step attack:
- Attacker deploys a malicious contract with a fallback function that calls withdraw() on the vulnerable contract.
- Attacker convinces the target owner to call the malicious contract (e.g., "claim your airdrop").
- The malicious contract forwards the call to the target contract.
- In the target contract, tx.origin == owner is true β withdraw succeeds, and funds are stolen.
Assumptions:
- Victim is the legitimate owner.
- They are tricked into initiating a transaction through a malicious intermediary.
β Fixed Code
contract SafeAuth {
address public owner;
constructor() {
owner = msg.sender;
}
function withdraw() external {
require(msg.sender == owner, "Not owner"); // β
use msg.sender instead
payable(msg.sender).transfer(address(this).balance);
}
}
π§ Contextual Severity
- context: "Default"
severity: H
reasoning: "Exploitable by phishing; bypasses basic access control."
- context: "High-profile admin-only contracts"
severity: C
reasoning: "Admin privilege loss can cause total fund drain or protocol compromise."
- context: "Contracts with no user interaction"
severity: L
reasoning: "If no EOAs interact externally, phishing risk is reduced."
π‘οΈ Prevention
Primary Defenses
- Never use tx.origin for access control.
- Use msg.sender instead, which reflects the immediate caller.
- Use role-based access control libraries like OpenZeppelinβs Ownable or AccessControl.
Additional Safeguards
- Educate users to avoid interacting with unverified contracts.
- Monitor for permission checks that depend on global transaction context.
- Avoid deeply nested contract calls where caller context may be ambiguous.
Detection Methods
- Slither: tx-origin detector.
- Compiler warnings if tx.origin is used.
- Manual audit for any usage of tx.origin in require(...) or access checks.
π°οΈ Historical Exploits
- Name: Wallet Contract Phishing Attack
- Date: 2023
- Loss: Complete wallet drain
- Post-mortem: Link to post-mortem
π Further Reading
β Vulnerability Report
id: LS16H
title: Unsafe tx.origin Usage
severity: H
score:
impact: 5
exploitability: 4
reachability: 3
complexity: 2
detectability: 5
finalScore: 4.1
π Justifications & Analysis
- Impact: High β attacker can gain unauthorized control over withdrawals or config changes.
- Exploitability: Feasible via phishing or malicious dApp interaction.
- Reachability: Limited to contracts that explicitly misuse tx.origin.
- Complexity: Moderate β attack setup is simple, but user interaction is required.
- Detectability: Very high β static tools like Slither catch this reliably.