Apaymenttoanattacker'saddresssimulatesperfectly.
Correct balances. No revert. Clean verdict. Every transaction-security product answers what will this transaction do — and none of them answer whether it is the transaction that was asked for.
Two channels. One comparison. On Solana and EVM.
On Solana we read the unsigned transaction. On EVM we read the EIP-712 authorization the agent is about to sign. Same question, checked against the same quote — offline, no RPC.
The quote can’t be forged by a compromised agent because the model never touches the channel it arrives on — it’s structured JSON from the server’s HTTP 402 response, sent before the transaction exists. On Solana the expected destination is derived from it deterministically; on EVM the signed authorization is recovered and compared field by field. Signing refuses anything else — offline, in about a millisecond, with no RPC.
Everything above costs you a revert. Change one variable — give the agent spending authority — and it stops being recoverable. There is no chargeback and no rollback.
On May 4, 2026 an attacker asked Grok to translate a Morse-code string. Grok decoded it, posted the plaintext publicly, and tagged a payment bot — which treated another AI’s public reply as authorisation and sent roughly 3B DRB to the attacker. SlowMist put the root cause at “loose coupling between AI outputs and the real asset execution layer.” Read the case study →
We read the leading provider’s API schema. Across the whole specification: zero matches for injection, directive or prompt. Their scan request carries one required field — “DApp domain proposing these transactions” — and no field at all for what the agent was told to do.
That is not a missing feature. The stack is shaped around a human approving a website’s request, and a headless agent has neither.
The constraint that makes the fix work: intent is never something the agent states. If it were a field the model filled in, a compromised model would fill in both sides and validate its own forgery. In x402 the quote arrives as JSON in the HTTP 402 response, before the transaction exists, on a channel the model never touches.
ALLOW pays the quoted merchant, quoted amount
REFUSE pays an ATTACKER instead
[X402-001] destination is not the account
derived from the quote
REFUSE pays the merchant but 900x the amount
[X402-002] amount does not match the quote
REFUSE pays correctly + approves a delegate
[X402-006] Approve — delegates spending
authority over the account
ABSTAIN garbage bytes
could not deserialize — refusing to
report it as safeChecked from the serialized transaction bytes you already hold, plus the quote you already received. ~1ms, no RPC.
ALLOW signs to transfer the quoted amount to
payTo, on the quoted token and chain
REFUSE authorization.to is not the quoted payTo
[X402-101] wrong recipient
REFUSE authorization.value is not the quote
[X402-102] wrong amount
REFUSE domain is a different token or chain
[X402-103] wrong token / wrong chain
REFUSE signature does not recover to from
[X402-104] not signed by the payer
REFUSE an Approve / Permit / Permit2 allowance
[X402-106] grants standing spend, not a
one-shot transfer
ABSTAIN unknown token, contract-wallet signer, or
a scheme we don't decode — never called safeThe agent signs an authorization, not a transaction. We recompute the EIP-712 digest, recover the signer, and compare against the quote. Offline, no RPC.
Offline conformance, not settlement. We verify that the transaction or authorization the agent is about to sign moves the quoted amount of the quoted token to the quoted payToon the quoted chain, and — on EVM — that the signature recovers to the stated payer. We do not check on-chain state: balances, existing allowances, whether a token is genuine, or whether a facilitator will submit it. We check that the token address matches the quoted asset — not that it “is real USDC.” Verified today: the exact scheme with EIP-3009. A Permit2 allowance or an ERC-7710 delegation grants standing authority to a spender rather than a one-shot transfer, so we refuse those by default — that delegated-spend shape is exactly what the guard exists to stop. Anything we don’t decode, we abstain and never report safe.