The attacker did something cheap. They generated an address whose first and last characters matched one the victim had recently sent to, and pushed a worthless transaction from it into the victim's history.
Later the victim needed that destination again. They copied it from their own transaction list, glanced at the ends, and sent 1,155 WBTC.
The decision point is not that they were careless. It is that their history had been written to by a stranger, and they treated it as a record of their own decisions.
This one has an unusual ending. The victim publicly offered a 10 percent bounty, negotiated, and the attacker returned more than 96 percent of the value. Do not read that as reassurance. It happened because the attacker decided it should, and F105-06 covers how rarely that is the outcome.
The previous lesson ended with a rule: if the device cannot tell you what you are signing, do not sign. This lesson is about the case where the device tells you clearly and you still get it wrong, because the thing it is clearly telling you is a hostile address that looks correct.
Your history is not yours
This is the idea people find hardest, so it goes first.
Anyone can send you anything. That includes tokens you did not ask for, transactions worth nothing, and transfers whose only purpose is to place an address into your wallet's list of addresses you have interacted with.
Your transaction history is not a private record of your decisions. It is a public log that strangers can append to. Once you understand that, address poisoning stops being clever and becomes obvious.
Copy it from the source of truth: the recipient's own message, the exchange's deposit page, the address book entry you created deliberately. Your history is a place attackers write to.
Why the ends do not work
Every wallet truncates. 0x7a25...9f3b. The interface does it to save space, and by doing so it teaches you to check exactly the eight characters an attacker will match.
Generating a vanity address with a chosen prefix and suffix is not exotic. It is a brute force search that anyone can run cheaply, and it gets cheaper every year. The middle of the address is where the collision would have to be, and the middle is what the interface hides.
An address is 40 hexadecimal characters. Matching the first four and last four means matching 8 of 40.
Each hex character is one of 16 values, so matching 8 specific characters is a 1 in 16 to the power of 8 search, which is roughly 1 in 4.3 billion.
That sounds protective until you notice it is a search an attacker runs once, offline, at their leisure, for a target worth eight figures. Four billion attempts on commodity hardware is minutes, not years.
The other 32 characters, the ones you never look at, are doing all of the actual work of making an address unique.
So the discipline is unglamorous: all of it, or none of it. Check every character, or accept that you did not check.
Check it on the device
Verification has to happen somewhere the attacker does not control.
If a compromised web page produced the request, reading the address on that same page proves nothing. It can display whatever it likes. The hardware device screen is the one surface the page cannot write to, which is the entire reason the screen exists.
The order that works:
- Get the address from the source of truth, not from history.
- Paste it, then look at the interface field.
- Look at the device screen and compare it to the source of truth, not to the interface. Two places can be wrong together.
- Confirm.
Clipboard hijacking is why step 3 is not redundant. Malware that watches the clipboard and swaps an address for its own is old, cheap, and still working: the Torg Grabber campaign hit 728 wallets in March 2026. Between your copy and your paste, the value can change. The device screen is downstream of the swap and will show you the truth.
I use a checksummed address, so a wrong one would be rejected.
EIP-55 checksumming catches typing errors and corruption. It does not catch a valid address belonging to someone else. A poisoned lookalike is a real, correctly checksummed address. Checksums protect against accident, never against intent.
Test transactions, honestly
Sending a small amount first is good advice for exactly one situation and useless for the rest.
It works when the risk is that the destination is wrong: a new counterparty, an exchange deposit address, a chain you have not used before. Send a small amount, confirm receipt with the recipient out of band, then send the rest.
It does nothing against anything from the previous lesson's standing-authority group. A test approval is still an approval. If the limit is unlimited, the size of the transaction that granted it is irrelevant. People send a test, see it arrive safely, and conclude the interaction is safe. The interaction was never the risk.
It also does nothing if you re-copy the address from history for the real send. That is precisely the autopsy above.
Contract spoofing
The same problem applies one level up. An interface can label anything. A panel reading "Official Router" is a string on a web page, with no more authority than any other string.
When the device shows a counterparty that differs from what the interface named, the device is right. Not "probably right." Right. The interface is the untrusted input; the device is the verification. If you find yourself reasoning about why the device might be confused, stop and treat that impulse as the signal it is.
Verification means every character, taken from the source of truth rather than your own history, and read on the device rather than in the page that asked. Truncated comparison checks the eight characters an attacker will have matched, and leaves the thirty-two that actually identify the address unread. A test transaction protects against a wrong destination and against nothing else.