Your Agent Just Paid for Nothing: 6 Attacks on x402 Payments - Ishween Kaur, SoFi
Read the talk
Six ways an x402 payment can go wrong
Ishween Kaur of SoFi tested both sides of an agent purchase. In one run, the buyer signed and paid 50 cents for a service listed at five cents. In a replay example, five requests could pass signature verification even though only one payment could settle.
From a talk by Ishween Kaur
At a glance
Ideas worth remembering
Compare the live 402 terms with the approved price, wallet and network before the buyer signs.
Reuse one payment number across retries and bind it to the purchased resource in storage shared by every paid route.
When a task authorizes one paid call, enforce that limit at execution. It stopped the premium purchase even after the model chose to proceed.
What should an agent be allowed to buy?
Watching one movie on Disney+ can mean creating an account, entering payment information, starting a subscription and remembering to cancel. Paying once for the movie sounds simpler. Now put an agent in the buyer’s seat. It needs one market data point to finish a report, and an API offers it for five cents. Before spending the money, the agent has three questions to resolve. Is this an approved seller? Is the price within budget? Is this the data the user authorized it to buy?
HTTP has long had a status code for payment required, 402. The code left open how software could make the payment. x402 supplies that exchange. A buyer requests data, and the seller returns a 402 with payment requirements. The buyer signs a payment and sends it to the seller, which passes it to a facilitator for verification and on-chain settlement. The seller can release the data as soon as the facilitator verifies the signature, or it can wait for the money to move.
The economics matter at both ends of the scale. A credit card fee can exceed the price of a data point that costs a cent or a third of a cent. Yet at ten cents per call, 10,000 calls move $1,000. Kaur found 20 ways to break the purchase sequence in a safe test environment. Six illustrate where a buyer can spend more than intended or a seller can deliver more than the buyer paid for.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
The price can change between discovery and signing
Kaur listed a service at five cents in the directory, then had the seller ask for 50 cents in the 402 payment header. The header supplied the terms the buyer actually signed. Without a guard, the payment settled at ten times the listed price. In a second run, a code check compared the two price fields before signing and blocked the purchase.
That comparison still allowed a seller to change the destination wallet or the network. A buyer expecting to pay on Base could receive terms specifying Ethereum or Solana. Checking the amount, wallet and network together lets the buyer catch a change even when the seller preserves the five-cent price.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Retries can multiply deliveries or charges
Consider a buyer that sends the same signed payment number five times. The signature checks out on every request. A seller that releases data on verification can therefore fulfill all five. At settlement, the chain accepts one payment and rejects the other four because the number must be unique. If each request releases a different record or activates a license, the chain catches the duplicate too late to protect the seller.
Kaur’s seller-side guard uses shared storage to track payment numbers already in progress or completed. A repeat request can receive the saved result once it is ready. The buyer needs the complementary rule when a reply times out. If three attempts each carry a fresh payment number, the chain can accept three charges for one summary. Reusing the original number keeps those attempts tied to one purchase.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Three ways to get a paid report for free
Even a single request can pass verification and then fail to settle because of insufficient funds or an inconsistent state. By then, a seller that delivered immediately has given the buyer the data. Waiting for settlement adds latency, a tradeoff Kaur would accept for confidential records, expensive per-request generation, provisioning or license activation. For data priced at $0.001, the business might reasonably accept the risk to serve the response faster.
A second route needs no signed payment at all. If two endpoints serve the same report and only one enforces the paywall, a buyer can call the other directly. Kaur’s test is to request every endpoint intended to be paid without supplying a payment. Each should return HTTP 402.
A cache can create a third route. The first buyer pays, the seller generates the report, and a cache saves the response under a public URL. The next buyer can retrieve the saved copy for free. Keeping the cache behind the seller’s payment check protects cached responses too. For confidential, expensive or individually generated responses that should never enter a cache, Kaur uses the Cache-Control: no-store header.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
One payment number can unlock two pages
Suppose both pages enforce payment, but each tracks purchases independently. Kaur sent payment number 16 to both. Each page saw a valid payment and delivered its data. Only one payment could settle. The shared record used for retries needs one more detail here. It must bind the payment number to the page it bought. A retry for that page can retrieve its saved result, while a request for a different page using number 16 gets HTTP 409 Conflict.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
A working service can belong to a lookalike seller
In Kaur’s account, the x402 Bazaar directory checks that a service works. It does not establish who operates the service or owns the destination wallet. She created a lookalike with a similar name, a different domain and wallet, and a lower price. Her agent tried to pick the cheaper listing. Its price comparison worked exactly as intended while steering it toward the attacker.
An enterprise can limit purchases to an allowlist of approved sellers. For workflows that need to discover new sources, Kaur proposed keeping approved, blocked and probationary sellers separately. A four- or 24-hour review window could give a human time to inspect what the buyer wanted, which seller it contacted and what came back. Approved entries need review too, since legitimate sellers change domains, wallets, prices, networks and coins.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
A seller’s reply turns five cents into 55
On Base Sepolia, Kaur used Llama 3.2 to decide what to do with a purchased summary. The seller’s response described the summary as truncated and pointed to a premium version. The agent followed the suggestion. Both the original five-cent payment and the additional 50-cent payment settled.
Kaur tried a regex filter for words such as “pay,” “tiers” and “premium.” A seller could avoid all three by hinting that analysts prefer another summary. A model judging whether the response contained an attack caught many cases in her experiments, but could still miss an indirect suggestion.
The original task supplied a simpler condition to enforce. The buyer had approval for one paid call that turn. Kaur locked the execution plan to that limit and repeated the experiment. The agent still decided to fetch the premium summary, but the guard blocked the second purchase. Its effectiveness in that run did not depend on detecting anything suspicious in the seller’s prose.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Trace a purchase before deciding what to block
Kaur started with one payment ID and followed it through the workflow. The resulting sequence should let an engineer reconstruct the buyer’s intent, identify the seller contacted and inspect its response. Seeing where the buyer signed and where the seller released data exposes decisions that a settlement record alone cannot explain.
For rollout, she proposed a shadow phase with 20 to 25 cases spanning successes and failures in the actual business workflow. Inspect each trace to decide where an alert is enough and where execution must stop. Then enforce the guards and rerun the same cases. A blocked second purchase is the desired outcome for a one-summary task. A seller delaying a $0.001 response until settlement may be paying a latency cost the business would prefer to avoid. The trace gives the team a specific decision to revisit in each case.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.