Phishing attack in Web3

From WEB3 Vulnerapedia
Jump to navigation Jump to search

Phishing attacks in Web3 represent a notable security concern impacting users and platforms within decentralized networks. These malicious activities employ deceptive methods to obtain sensitive information or perform harmful actions, posing a threat to the integrity and trust essential to the Web3 ecosystem. Recognizing the dynamics and consequences of phishing attacks is pivotal in mitigating risks and upholding the security of decentralized systems.

Technical details


In order to block an address from interacting with your contract, tx.origin would be more appropriate because the owner of the address can’t use a contract as a middleman to circumvent your block. It’s important to note that this block only blocks an address, not a person.


The msg.sender is the address that has called or initiated a function or created a transaction. This address could be of a contract or even a person. To identify the initiator of a transaction or current call, we can make use of the globally available msg object.

tx.orgin vs msg.sender

Phishing attack in Solidity

In this example the function to send ether is used.

contract Wallet {
    address public owner;

    constructor() payable {
        owner = msg.sender;

    function transfer(address payable _to, uint _amount) public {
        require(tx.origin == owner, "Not owner");

        (bool sent, ) ={value: _amount}("");
        require(sent, "Failed to send Ether");

In this contract ether can be transferred to an account and in order to verify that the right EOA or Smart Contract is triggering the transfer, or in other words, to make sure the owner of the wallet is the one making the transfer, it is using:

require(tx.origin == owner, "Not owner")

Which as illustration above allows someone who didn’t trigger the function directly to appear as the owner.

An attacker can exploit it.

contract Attack {
    address payable public owner;
    Wallet wallet;

    constructor(Wallet _wallet) {
        wallet = Wallet(_wallet);
        owner = payable(msg.sender);

    function attack() public {
        wallet.transfer(owner, address(wallet).balance);

The attacker would have to trick the owner of the Wallet contract to trigger attack() function by phishing emails, messages, etc.


In order to protect contracts from phishing msg.sender instead of tx.origin must be used. And the transfer() function should look like this:

function transfer(address payable _to, uint _amount) public {
    require(msg.sender == owner, "Not owner");

    (bool sent, ) ={value: _amount}("");
    require(sent, "Failed to send Ether");

require() was changed to check that the owner is msg.sender to protect the wallet from phishing attacks.