Skip to content

Phishing Attacks Targeting Crypto Users

💡
Before you start

Python 3 and a terminal — nothing else. macOS and Linux have it already; on Windows install it from python.org with “Add python.exe to PATH” ticked, then check with python3 --version. Every module used below ships with Python, so there is nothing to install.

Nothing here visits a website. The fake domains are typed into your own files and examined offline — you will never be asked to open a suspicious link to see what happens, which is advice that gets people robbed. What you are building is the habit of answering “which site is this actually?” with a check instead of a glance.

Why Crypto Phishing is Different

Traditional phishing steals passwords, which can often be reset. Crypto phishing steals private keys or seed phrases, which cannot be reset. One successful phishing attack can permanently drain your entire wallet in seconds. There is no customer support to call, no chargeback to file, and no way to reverse the transaction.

Fake Wallet Websites

Scammers create pixel-perfect copies of popular wallet interfaces:

  • Fake versions of MetaMask, Phantom, Ledger Live, and other popular wallet sites
  • URLs use subtle tricks: metamask.io vs metamask-io.com vs rnetamask.io (rn looks like m)
  • These sites ask you to "import your wallet" by entering your seed phrase
  • The moment you enter your seed phrase, all funds are automatically swept
⚠️
A legitimate wallet will never ask for your seed phrase through a website

Seed phrases are only entered directly into wallet software or hardware devices during recovery. Any website asking for your seed phrase is a phishing site, without exception.

Malicious Browser Extensions

  • Fake wallet extensions published to Chrome Web Store or Firefox Add-ons with names similar to real wallets
  • Some request excessive permissions that allow them to read all website data
  • They may overlay fake transaction confirmations or modify displayed addresses
  • Always install wallet extensions from the official project website link, never from searching the extension store directly

Clipboard Hijacking

Clipboard hijacking malware monitors your clipboard for cryptocurrency addresses. When you copy an address to send funds:

  • The malware detects the address format (Bitcoin, Ethereum, etc.)
  • It silently replaces the copied address with the attacker's address
  • When you paste, you paste the attacker's address without realizing it
  • You send funds directly to the attacker thinking you sent them to the intended recipient
💡
Always verify the full address after pasting

Check the first and last 6-8 characters of the address after pasting. This takes five seconds and can save you from losing everything.

Address Poisoning

A newer and particularly insidious attack:

  • The attacker generates a wallet address that matches the first and last few characters of an address you regularly send to
  • They send a tiny transaction (dust) from this lookalike address to your wallet
  • This transaction appears in your history, looking like the address you normally use
  • Next time you need to send funds, you might copy the attacker's lookalike address from your transaction history instead of the real one

Defense: never copy addresses from transaction history. Always use your address book or get the address directly from the intended recipient.

The same reasoning applies to the tokens themselves. A counterfeit can copy a familiar name, ticker and icon exactly, so a token's identity has to be confirmed from its contract address rather than from the label a wallet displays — see How to Verify a Token Contract Address.

Fake Support Channels

  • Scammers monitor social media for users posting about wallet problems
  • They DM the user pretending to be official support, often within minutes
  • They direct the user to a "support tool" or "wallet repair site" that harvests seed phrases
  • Real support teams will never DM you first and will never ask for your seed phrase

Email Phishing for Exchange Accounts

  • Fake "security alert" emails from exchanges urging you to log in immediately
  • Links lead to convincing replicas of the exchange login page
  • After capturing your credentials, attackers log in and initiate withdrawals
  • Some phishing kits also intercept 2FA codes in real time (adversary-in-the-middle attacks)

How to Protect Yourself

  • Bookmark official sites and always navigate from bookmarks, never from search results or links
  • Verify URLs character by character before entering any credentials
  • Use a hardware wallet that shows transaction details on its own screen
  • Enable anti-phishing codes on exchanges that support them
  • Verify the full address after pasting, before every transaction
  • Never enter your seed phrase into any website
  • Use hardware-based 2FA (security keys) when possible, as they are phishing-resistant

Now Catch a Phishing Domain Yourself, in Five Steps

Crypto phishing does not beat your judgement — it beats your eyes. In the next fifteen minutes you will hold two domain names that are visually identical and prove they are different sites, watch what your browser really requests when you click one, build a two-line detector that catches the whole trick, learn to read a web address in the only direction that tells the truth, and finally put a number on the “approve” button that empties wallets. Every line of output below came from running these files.

1
Hold two identical-looking domains and prove they are different

Go: open a terminal in a folder you can write to, for instance cd ~/Desktop (Windows: cd %USERPROFILE%\Desktop).

Do: save this as lookalike.py and run python3 lookalike.py. Copy it exactly — the fourth character of the second name is a Cyrillic letter, and copying by hand will destroy the whole point.

real = "binance.com"
fake = "binаnce.com"          # the 'a' here is Cyrillic U+0430

print("they look the same :", real, fake)
print("they are the same  :", real == fake)
print()
for label, name in (("real", real), ("fake", fake)):
    print(label, "->", " ".join(f"U+{ord(c):04X}" for c in name[:8]))

You should see: two names your eyes cannot separate, and one position where the computer can:

they look the same : binance.com binаnce.com
they are the same  : False

real -> U+0062 U+0069 U+006E U+0061 U+006E U+0063 U+0065 U+002E
fake -> U+0062 U+0069 U+006E U+0430 U+006E U+0063 U+0065 U+002E

Position four: U+0061 is the Latin letter a, U+0430 is the Cyrillic letter а. They are drawn identically in almost every font on earth and are completely different characters, so they are completely different domains, owned by different people. No amount of careful looking will separate them.

If not: if the second line prints True, your editor “helpfully” normalised the Cyrillic character back to Latin when you pasted — use a plain editor such as Notepad, TextEdit in plain-text mode, or nano. If you see SyntaxError: invalid character, a smart-quote replaced a straight quote; retype the quotation marks.

2
See what your browser actually requests

Go: same folder.

Do: save this as punycode.py and run it. Domain names can only travel as ASCII, so anything else is converted first — and the conversion is visible.

fake = "binаnce.com"

print("what your eyes read     :", fake)
print("what the browser fetches:", fake.encode("idna").decode())

You should see: the disguise falling off:

what your eyes read     : binаnce.com
what the browser fetches: xn--binnce-5nf.com

That xn-- prefix marks a name containing non-ASCII characters. Most browsers show it in the address bar for exactly this reason, so a wallet or exchange address that suddenly reads xn-- is not a glitch — it is the warning. Some browsers only show it for certain scripts, which is why the next step exists.

If not: UnicodeError: label empty or too long means the string lost its Cyrillic character in copying, leaving something IDNA cannot encode. If it prints binance.com unchanged, the same thing happened — a pure-ASCII name converts to itself.

3
Build the detector, and run it on four names

Go: same folder. Two lines is all the defence needs.

Do: save this as detect.py and run it.

def looks_safe(domain):
    bad = [c for c in domain if ord(c) > 127]
    return "SAFE (plain ASCII)" if not bad else \
           "SUSPICIOUS: " + ", ".join(f"{c!r} = U+{ord(c):04X}" for c in bad)

for d in ["binance.com", "binаnce.com", "ledger.com", "lеdger.com"]:
    print(f"{d:16s} {looks_safe(d)}")

You should see: the two impostors named, with the exact character that gives them away:

binance.com      SAFE (plain ASCII)
binаnce.com      SUSPICIOUS: 'а' = U+0430
ledger.com       SAFE (plain ASCII)
lеdger.com       SUSPICIOUS: 'е' = U+0435

Keep this file. When a link arrives by email, message or a search result, paste the domain into the list and run it. It takes three seconds and catches an attack class that careful reading cannot.

If not: if every line says SAFE, the Cyrillic characters were lost in copying — go back to step 1 and copy from the page again. Legitimate international domains do contain non-ASCII characters, so treat SUSPICIOUS as “stop and verify by another route”, not as proof of fraud.

4
Read a web address in the only direction that tells the truth

Go: same folder. This step needs no Unicode trickery at all — these domains are honest ASCII, and still lie.

Do: save this as whereami.py and run it.

from urllib.parse import urlparse

urls = [
    "https://app.uniswap.org/swap",
    "https://app.uniswap.org@wallet-drainer.xyz/connect",
    "https://metamask.io.security-check.app/verify",
    "https://trezor.io/start",
]

for u in urls:
    host = urlparse(u).hostname
    print(f"{host:32s} <- {u}")

You should see: two of the four going somewhere other than where they appear to:

app.uniswap.org                  <- https://app.uniswap.org/swap
wallet-drainer.xyz               <- https://app.uniswap.org@wallet-drainer.xyz/connect
metamask.io.security-check.app   <- https://metamask.io.security-check.app/verify
trezor.io                        <- https://trezor.io/start

Two separate tricks. Everything before an @ in a web address is ignored as a username, so the second link goes to wallet-drainer.xyz while displaying a name you trust. And in the third, metamask.io is merely a subdomain of security-check.app — anyone can create it in thirty seconds. Ownership is decided by the last two labels before the first slash, read right to left. Everything to their left is chosen by whoever owns them.

If not: if the second line prints app.uniswap.org, the @ was dropped in copying. If hostname returns None, the URL is missing its https:// prefix.

5
Put a number on the button that empties wallets

Go: same folder. The last step of a crypto phishing attack is rarely “send us your coins” — it is a token approval that looks routine.

Do: save this as approval.py and run it.

MAX = 2**256 - 1
ONE_TOKEN = 10**18

print("amount the popup is asking you to approve:")
print("  raw   :", MAX)
print("  tokens:", f"{MAX // ONE_TOKEN:,}")
print()
print("what a 50-token swap actually needs:")
print("  raw   :", 50 * ONE_TOKEN)
print("  tokens: 50")

You should see: the two numbers side by side:

amount the popup is asking you to approve:
  raw   : 115792089237316195423570985008687907853269984665640564039457584007913129639935
  tokens: 115,792,089,237,316,195,423,570,985,008,687,907,853,269,984,665,640,564,039,457

what a 50-token swap actually needs:
  raw   : 50000000000000000000
  tokens: 50

That first number is the largest value the token standard can hold, and wallets often render it as “Unlimited” or simply as a wall of digits nobody reads. Approving it hands a contract permission to move that token out of your wallet at any point in the future, with no further prompt. Before approving anything, look for the amount and check it is roughly the size of the trade you are making. A swap for 50 tokens that requests an unlimited allowance is asking for something it does not need.

If not: ValueError: Invalid format specifier means the :, inside the f-string was mistyped. If the token line looks rounded or ends in zeros, you used / instead of // — ordinary division loses precision at this size, which is itself a good reason to distrust a displayed amount.

🎉
Check yourself before moving on

Without scrolling up: a search result shows https://ledger.com.wallet-verify.net/recover and the page looks perfect. Which site are you on, why did the padlock and the “https” not help, and what is the one thing that page will eventually ask for? Answer: you are on wallet-verify.net — ownership is the last two labels, and “ledger.com” is just a subdomain the attacker created. The padlock only means the connection to that attacker is encrypted; anybody can obtain a certificate for a domain they own, in minutes, for free. What it will ask for is your recovery phrase, usually framed as “validate”, “sync” or “restore your wallet” — and no genuine wallet, exchange or support agent ever needs it.

Now do it without the page: take the last three links that reached you by email or message — any links, not only crypto ones — and run each through both detect.py and whereami.py. Write down the registrable domain for each one before you look at what you expected. Doing this on ordinary mail is how the habit becomes automatic before the day it matters.

Summary

  • Crypto phishing is more dangerous than traditional phishing because losses are irreversible
  • Fake wallet sites, malicious extensions, and fake support are the most common vectors
  • Clipboard hijacking and address poisoning silently replace destination addresses
  • Always verify full addresses, bookmark official sites, and never enter seed phrases online
🎉
You can now defend against crypto phishing!

Next, learn about rug pulls and how to spot fraudulent crypto projects before they take your money.