DEV Community

ohmygod
ohmygod

Posted on

Address Poisoning After Fusaka: How Ethereum's Fee Cut Handed Scammers a 612% Boost — And What You Can Do About It

Ethereum's Fusaka upgrade shipped in December 2025 with a simple promise: cheaper transactions for everyone. Fees dropped roughly 67%. Rollups cheered, NFT minters cheered, and address-poisoning bots really cheered — because the same fee reduction that made micro-payments viable also made industrialized fraud dirt-cheap.

By March 2026 the numbers are staggering. Etherscan reported a 612% surge in USDT dust transfers under $0.01 since Fusaka. A crypto influencer lost $24 million in a single poisoned-address paste in March alone. The technique isn't new — 17 million attempts were logged between 2022 and 2024 — but the economics have fundamentally shifted.

Let's break down exactly how this attack works at the transaction level, why Fusaka made it worse, and what developers and users can do right now.


How Address Poisoning Actually Works

Address poisoning exploits a UX flaw, not a smart-contract flaw. The attack chain:

  1. Monitor: A bot watches the mempool (or indexed on-chain history) for transfers from a target wallet.
  2. Generate: For every legitimate recipient the target interacts with, the bot generates a vanity address that matches the first 4–6 and last 4 characters — the only characters most wallets display.
  3. Dust: The bot sends a tiny transfer (often $0.001 USDT) from the lookalike address to the target wallet.
  4. Wait: The poisoned transaction now sits in the victim's history, visually indistinguishable from the real one.
  5. Harvest: When the victim copies an address from their history for a future transfer, they grab the poisoned one. Funds go to the attacker. Irreversible.

The Vanity Address Math

How hard is it to find a collision on the first 4 and last 4 hex characters? Each hex character is 4 bits, so 8 characters = 32 bits = roughly 4.3 billion combinations. A GPU running at 100M keys/second finds a match in about 43 seconds. With a rented cloud GPU at $1/hour, an attacker can generate one poisoned address for $0.012.

Pre-Fusaka, sending a dust transfer on Ethereum cost $0.50–$2.00 in gas. Post-Fusaka, it costs $0.05–$0.15. That 10x reduction in per-transfer cost makes spray-and-pray campaigns economically viable at massive scale.

Pre-Fusaka cost per poisoning attempt:  ~$2.00 gas + $0.01 vanity gen = $2.01
Post-Fusaka cost per poisoning attempt: ~$0.10 gas + $0.01 vanity gen = $0.11

ROI at $50K average theft per success:
  Pre-Fusaka:  need 1 hit per 24,875 attempts (0.004% success rate)
  Post-Fusaka: need 1 hit per 454,545 attempts (0.0002% success rate)
Enter fullscreen mode Exit fullscreen mode

The economics just got 18x more forgiving for attackers.


Stablecoin Dust: The Preferred Weapon

Why do attackers favor USDT/USDC dust over ETH transfers?

  1. Stablecoin transfers show up prominently in wallet UIs because users filter by token. A $0.001 USDT transfer looks like a normal USDT interaction.
  2. No value fluctuation — the attacker doesn't risk losing money on the dust itself.
  3. ERC-20 transfer() events are indexed separately from native ETH transfers, so they appear in token-specific history views.

Post-Fusaka data from Etherscan:

Token Pre-Fusaka dust/day Post-Fusaka dust/day Increase
USDT ~12,000 ~85,400 612%
USDC ~4,200 ~19,700 369%
DAI ~1,800 ~8,100 350%

Real Casualties

The $24M March 2026 Incident

A well-known crypto influencer was transferring funds between personal wallets — a routine operation they'd done dozens of times. Their wallet displayed:

Legit:    0x7a3F...8c2D
Poisoned: 0x7a3F...8c2D  (different middle bytes, same visual prefix/suffix)
Enter fullscreen mode Exit fullscreen mode

They copied from history. $24 million in stablecoins went to the attacker's address. The funds were laundered through Tornado Cash forks within 90 minutes.

The $50M December 2025 Theft

Days after Fusaka went live, a DeFi treasury wallet was drained of $50M using the same technique — the largest single address-poisoning theft on record.


Why Wallet UIs Are the Real Vulnerability

This isn't a protocol bug. It's a design bug in how wallets present information:

MetaMask default:    0x7a3F...8c2D  (8 visible chars out of 40)
Trust Wallet:        0x7a3F...8c2D
Rabby:               0x7a3F...8c2D  (but highlights new addresses)
Enter fullscreen mode Exit fullscreen mode

Only 20% of the address is visible. The other 80% — the part that actually differs between the legit and poisoned addresses — is hidden behind an ellipsis.

What Good UX Would Look Like

// Pseudocode for a safer address display
function displayAddress(address, knownContacts) {
    if (knownContacts.has(address)) {
        return `✅ ${knownContacts.getName(address)}`;
    }

    // Show MORE of the address for unknown recipients
    // Highlight bytes that differ from similar addresses in history
    const similar = findSimilarInHistory(address);
    if (similar.length > 0) {
        return highlightDifferences(address, similar[0]);
        // e.g., "0x7a3F██████████████████████████████8c2D"
        //        vs "0x7a3F▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓8c2D"
    }

    return fullAddress(address); // Show all 42 chars for unknown
}
Enter fullscreen mode Exit fullscreen mode

Defense: What Developers Should Build

1. Address Book Enforcement

// Force users to save addresses before sending large amounts
const LARGE_TRANSFER_THRESHOLD = 10_000; // USD

async function validateTransfer(to: string, amountUSD: number) {
    if (amountUSD > LARGE_TRANSFER_THRESHOLD) {
        const contact = await addressBook.lookup(to);
        if (!contact) {
            throw new Error(
                `Sending $${amountUSD} to an address not in your contacts. ` +
                `Please add this address to your address book first.`
            );
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

2. Poisoning Detection in Transaction History

def detect_poisoning(tx_history: list[dict]) -> list[dict]:
    """Flag transactions that look like address poisoning attempts."""
    warnings = []
    known_recipients = set()

    for tx in tx_history:
        recipient = tx['to']
        amount_usd = tx['value_usd']

        # Check for dust transfers from addresses similar to known contacts
        if amount_usd < 0.10:
            for known in known_recipients:
                if (recipient[:6] == known[:6] and 
                    recipient[-4:] == known[-4:] and 
                    recipient != known):
                    warnings.append({
                        'tx_hash': tx['hash'],
                        'poisoned_addr': recipient,
                        'mimics': known,
                        'severity': 'HIGH',
                        'reason': 'Dust transfer from address mimicking known contact'
                    })

        if amount_usd > 1.0:
            known_recipients.add(recipient)

    return warnings
Enter fullscreen mode Exit fullscreen mode

3. Smart Contract Allowlists

For treasury wallets and DAOs, enforce allowlists at the contract level:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract SafeTreasury {
    mapping(address => bool) public allowedRecipients;
    mapping(address => bool) public governors;

    uint256 public constant ALLOWLIST_DELAY = 24 hours;
    mapping(address => uint256) public pendingAdditions;

    modifier onlyGovernor() {
        require(governors[msg.sender], "Not governor");
        _;
    }

    // Two-step process: propose, then confirm after delay
    function proposeRecipient(address recipient) external onlyGovernor {
        pendingAdditions[recipient] = block.timestamp + ALLOWLIST_DELAY;
        emit RecipientProposed(recipient, block.timestamp);
    }

    function confirmRecipient(address recipient) external onlyGovernor {
        require(pendingAdditions[recipient] != 0, "Not proposed");
        require(block.timestamp >= pendingAdditions[recipient], "Delay not met");
        allowedRecipients[recipient] = true;
        delete pendingAdditions[recipient];
        emit RecipientConfirmed(recipient);
    }

    function transfer(address token, address to, uint256 amount) external onlyGovernor {
        require(allowedRecipients[to], "Recipient not allowlisted");
        IERC20(token).transfer(to, amount);
    }

    event RecipientProposed(address indexed recipient, uint256 timestamp);
    event RecipientConfirmed(address indexed recipient);
}
Enter fullscreen mode Exit fullscreen mode

Defense: What Users Should Do Right Now

The 5-Second Rule

Before confirming any transfer over $100:

  1. Open the recipient address in a block explorer (don't copy from history)
  2. Compare ALL 42 characters against your intended recipient
  3. Send a test transaction first ($1) and verify receipt
  4. Use address book / contacts — never copy from transaction history
  5. Check for dust: if you see tiny transfers from addresses similar to your contacts, your wallet has been targeted

Wallet Settings Checklist

☐ Enable address book / contacts feature
☐ Add all frequently-used addresses as named contacts  
☐ Turn on "confirm full address" if your wallet supports it
☐ Enable transaction simulation (Rabby, Fire, Pocket Universe)
☐ Set up a multisig for amounts > $10K (Safe, Squads)
☐ Use a hardware wallet for signing (Ledger, Trezor)
Enter fullscreen mode Exit fullscreen mode

The Bigger Picture: Cheap Fees Are a Double-Edged Sword

Every protocol upgrade that reduces transaction costs shifts the economics of abuse. Fusaka isn't unique — the same pattern played out when Arbitrum and Optimism launched with sub-cent fees, and spam/phishing on L2s spiked immediately.

The lesson for protocol designers: fee reductions must ship alongside anti-spam tooling. Some proposals already in discussion:

  • EIP-7762: Minimum fee for ERC-20 transfers to addresses with no prior interaction (anti-dust)
  • Wallet-level ML classifiers: Flag transactions from addresses generated within the last 48 hours that match known contact patterns
  • Etherscan's address-tagging API: Real-time labels for known poisoning addresses, consumable by wallets

The Fusaka address-poisoning surge is a textbook example of how improving one metric (transaction cost) can degrade another (user safety) when security isn't considered as a first-class design constraint.


Key Takeaways

  1. Address poisoning is now industrialized — 612% surge in stablecoin dust post-Fusaka
  2. The attack costs $0.11 per attempt — economically viable at any scale
  3. It's a UX bug, not a protocol bug — wallets showing 20% of addresses is the root cause
  4. Developers: build poisoning detection, address books, and contract-level allowlists
  5. Users: never copy addresses from transaction history; always verify all 42 characters
  6. Protocol designers: fee reductions need anti-spam countermeasures shipped in parallel

This article is part of the DeFi Security Research series. Follow for weekly deep-dives into the vulnerabilities, exploits, and defense patterns shaping Web3 security.

Top comments (0)