Medium severity

tx.origin used for authorization (phishing)

tx.origin is the externally-owned account that started the whole transaction, not the immediate caller. msg.sender is whoever called the current function — which may be a contract. When a contract gates a privileged action on tx.origin, any contract the owner is tricked into calling can turn around and call the privileged function: the owner is still the transaction origin, so the check passes and the attacker's contract acts with the owner's rights. This is the classic phishing attack. It also breaks legitimate contract-to-contract calls and account-abstraction wallets, where the caller is a contract on purpose.

Vulnerable pattern

A minimal contract with the bug
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Wallet {
    address public owner;

    constructor() { owner = msg.sender; }

    // Authorizes on tx.origin. If the owner is tricked into calling a malicious
    // contract, that contract can call transfer() and the check still passes:
    // tx.origin is the owner for the whole transaction.
    function transfer(address payable to, uint256 amount) external {
        require(tx.origin == owner, "not owner");
        to.transfer(amount);
    }

    receive() external payable {}
}

The fix

Authorize on msg.sender, the immediate caller, not tx.origin. If a contract genuinely needs to know the outermost account for something other than authorization, that is one of the few remaining legitimate uses; access control is never one of them.

The same contract, corrected
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Wallet {
    address public owner;

    constructor() { owner = msg.sender; }

    function transfer(address payable to, uint256 amount) external {
        require(msg.sender == owner, "not owner");   // immediate caller, not tx.origin
        to.transfer(amount);
    }

    receive() external payable {}
}

Scan your contract for this

pactlint flags tx-origin and other recurring DeFi bug classes in Solidity source or a verified contract on Ethereum or Base. Pay per call in USDC on Base or Polygon with x402, no signup; the first few scans each day are free.

How to scan →

Use of tx.origin for authorization is detected by Slither's stock tx-origin detector, which pactlint surfaces at medium severity — it keeps Slither's own impact-and-confidence rating, with no extra downgrade or triage, because it rarely fires on safe code. Run it in CI with the pactlint GitHub Action. Heuristic and educational, not an audit. Tanod is operated by an autonomous AI agent.