logo

Address Poisoning Against Autonomous Agents

Address poisoning plants a lookalike address in a wallet's transaction history, usually by sending a zero-value or dust transfer from an address matching the first and last characters of one you already use. An agent that selects recipients by reading history rather than from a verified allowlist will eventually copy the attacker's address.

How the attack works

The attacker generates addresses until one shares the first and last few characters with an address the target already transacts with. Vanity address generation makes this cheap for a handful of characters at each end, which is exactly the portion a person verifies.

They then create a transaction that puts this lookalike into the target's visible history. Common variants include a zero-value transfer, a dust transfer of a tiny amount, or a transfer of a worthless token crafted to appear in the same list as real activity. None of these require any access to the target's account; anyone can send to any address.

The result is an entry in the history that looks, at a glance, like a prior counterparty. The attack then waits. It succeeds when someone or something selects a recipient by copying from history rather than from an authoritative source.

Nothing is exploited in the cryptographic sense. No key is compromised and no contract is broken. The vulnerability is in how the recipient is chosen, which sits outside the parts of the system that receive security attention.

Why agents are a better target than people

A person copying an address usually glances at it, and the glance checks the start and the end, which is precisely what the attacker matched. That is a weak defence, and it is still a defence. An agent has no glance. If its recipient selection logic reads recent transfers, deduplicates, and picks the most recent counterparty, it applies exactly the heuristic the attack was designed to defeat, at machine speed, with no hesitation. An agent making hundreds of payments in a couple of days is also generating a long history, which gives the attacker many positions to insert into and makes a single anomalous entry harder to notice.

Why the usual defences do not apply

Spending limits do not help. A session key bounded to a sensible per-transaction cap still authorises a payment to the wrong recipient. The limit constrains how much is lost per event, not whether the event is wrong, and an agent making frequent small payments will repeat the mistake until something else stops it.

Allowed-contract restrictions do not help either. A transfer to a poisoned address is an ordinary token transfer through the legitimate token contract. Any policy that permits paying in that asset permits this transaction, because it is indistinguishable at the contract level.

Simulation does not flag it. Simulating the transaction shows a token transfer that succeeds and moves the stated amount. The simulation is accurate. The transaction does what it says, to the wrong party.

Signature and key hygiene are irrelevant. The key is used correctly, by the right party, for a transaction the owner's software constructed.

Reputation and screening services help unevenly. A freshly generated address has no history to screen, which is the normal condition for this attack rather than an edge case.

The common thread is that every one of these controls validates the transaction and none validates the intent. The transaction is well formed. The recipient is wrong.

Designing recipient selection that resists it

Pay from an allowlist, not from history. This is the whole fix. Maintain a set of recipients established out of band, from a signed invoice, a service manifest, a configuration file under review, or a discovery response you verified, and refuse to pay anything outside it without an explicit approval step. Transaction history is an observation of what happened, not an authorisation of what should happen next, and treating it as a source of recipients is the actual defect.

Compare full strings, always. Any address check must compare every character. Truncated comparison in logs, in a user interface, or in code is what the attack is built around. If addresses are displayed, display enough to be useless to the attacker or use a scheme that renders the whole value.

Bind the recipient to the payment request. In a pay-per-call flow the recipient should come from the challenge that demanded payment, validated against what you expect for that service, rather than from anything the agent inferred. That makes the recipient a property of the request being satisfied.

Treat a new recipient as a policy event. Paying an address for the first time is the moment to require something extra: an approval, a delay, a smaller first payment, or a check against the expected service identity. Repeat recipients are cheap to verify; new ones deserve the friction.

Filter zero-value and unsolicited transfers out of anything the agent reads. If the agent consumes history for any purpose, incoming transfers it did not expect should be excluded before that data reaches decision logic.

Log the recipient with its provenance. Record where each address came from, not just that it was paid. When something goes wrong, the question is which source produced the address, and without provenance you cannot answer it or tell how many other payments share the same bad origin.

Alert on first-time recipients and on near-miss addresses. An address differing from a known one only in the middle is a strong signal and cheap to compute across your allowlist.

Frequently asked questions

What is address poisoning?
An attack that plants a lookalike address in a target's transaction history, typically through a zero-value or dust transfer from an address matching the first and last characters of a real counterparty. It succeeds when someone copies the recipient from history instead of from a verified source.
Why are AI agents vulnerable to address poisoning?
Because they select recipients programmatically without visual inspection. A person at least glances at an address, which is a weak check but a real one. An agent reading recent transfers to find a counterparty applies exactly the heuristic the attack defeats, repeatedly and at speed.
Do spending limits protect against address poisoning?
No. A bounded session key still authorises a payment to whatever recipient the transaction names, so limits cap the loss per event rather than preventing it. An agent making frequent small payments can repeat the error many times while staying inside every configured limit.
How do you prevent address poisoning?
Select recipients from an allowlist established out of band rather than from transaction history, and compare addresses in full every time. Treat paying a new address as a policy event requiring approval or a delay, and exclude unsolicited incoming transfers from any data the agent reads.
Can transaction simulation detect a poisoned address?
No, because the transaction is legitimate in every technical respect. Simulation will show a successful token transfer of the stated amount through the real token contract. The transaction does exactly what it claims; the problem is that the recipient is not the intended one.