<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Boundra</title>
    <description>The latest articles on DEV Community by Boundra (@boundra).</description>
    <link>https://dev.to/boundra</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4207763%2F903306dd-a786-4be4-93f4-43634b6e380b.png</url>
      <title>DEV Community: Boundra</title>
      <link>https://dev.to/boundra</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/boundra"/>
    <language>en</language>
    <item>
      <title>Your AI agent will sign any amount a server declares — we measured it on mainnet</title>
      <dc:creator>Boundra</dc:creator>
      <pubDate>Mon, 26 Oct 2026 07:12:18 +0000</pubDate>
      <link>https://dev.to/boundra/your-ai-agent-will-sign-any-amount-a-server-declares-we-measured-it-on-mainnet-2p35</link>
      <guid>https://dev.to/boundra/your-ai-agent-will-sign-any-amount-a-server-declares-we-measured-it-on-mainnet-2p35</guid>
      <description>&lt;p&gt;In October 2026, a group of strangers on the internet converged on an uncomfortable fact about the x402 payment protocol — the HTTP-native standard that lets AI agents pay for resources with stablecoins:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The official client will sign whatever amount a server declares, as long as it fits under your spending cap.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not because of a bug in the signature scheme. Not because of a broken facilitator. Because the client's only defense is a &lt;em&gt;cap&lt;/em&gt; — and a cap answers "how much is too much in total", never "is this the price I agreed to".&lt;/p&gt;

&lt;p&gt;This is the story of how that gap was found, measured on Base mainnet, cross-checked by three independent implementations, and — within 72 hours — fixed in a PR to the official SDK. It is also the story of why agent payments need a policy layer, and what we are building about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The finding
&lt;/h2&gt;

&lt;p&gt;It started with &lt;a href="https://github.com/x402-foundation/x402/issues/3866" rel="noopener noreferrer"&gt;x402 issue #3866&lt;/a&gt;: a report that the official TypeScript client, when it receives a &lt;code&gt;402 Payment Required&lt;/code&gt; response, selects a payment requirement, checks it against a per-payment spending cap, and signs — without ever comparing the declared amount to anything the caller actually intended to pay.&lt;/p&gt;

&lt;p&gt;The attack doesn't need to be dramatic. A merchant server (or a compromised one, or a malicious proxy rewriting a 402) declares 10× the price mid-session. Your agent's $1 cap happily covers a $0.10 charge for a resource that cost $0.01 yesterday. No human sees a checkout page — there is no checkout page. That is the entire point of agent payments, and exactly why the gap matters.&lt;/p&gt;

&lt;p&gt;Three independent implementations verified the behavior within two days:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Boundra&lt;/strong&gt; (us) replayed the published S-BS-06 fixture corpus through our policy engine — &lt;a href="https://github.com/gobeyondfj-cmd/boundra/tree/main/fixtures/s-bs-06" rel="noopener noreferrer"&gt;6/6 agreement with the control-mode gate&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tanilo's x402-guard&lt;/strong&gt; reproduced it at the hook level with a mocked loopback seller.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;402Shield&lt;/strong&gt; mapped it model-to-model against their payment-intent drift approach.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Same verdict everywhere: the cap is not a price check.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then someone measured mainnet
&lt;/h2&gt;

&lt;p&gt;The strongest moment in the thread came from &lt;strong&gt;Agentic Finance Graph&lt;/strong&gt;, who ran a settlement-side measurement on Base mainnet (Oct 12–23, 2026): across 80 Bazaar-listed sellers with ≥20 settlements each — &lt;strong&gt;32,605 settlements totaling $18,950.78&lt;/strong&gt; — they found:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;1,126 settlements (3.5%) were ≥10× the seller's own median price&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;25 settlements were both ≥100× and ≥$1&lt;/strong&gt;, totaling $1,928.23&lt;/li&gt;
&lt;li&gt;The largest: &lt;strong&gt;$588.00 paid to a seller whose median price is $0.01&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everyone in the thread — including the measurer — is careful to frame this correctly: on-chain, these shapes are indistinguishable from legitimate usage-based pricing, so read it as &lt;strong&gt;the ceiling of the overcharge vector, not evidence of exploitation&lt;/strong&gt;. The 13 payers behind the big cases were single purchases, not loops.&lt;/p&gt;

&lt;p&gt;But that ceiling establishes something crucial: amounts far above a seller's usual price settle on mainnet &lt;em&gt;in the normal course of things&lt;/em&gt;. If a caller-side price expectation existed, it would have had something to act on. Today, nothing acts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: expectedAmount in the official SDK
&lt;/h2&gt;

&lt;p&gt;Discussion converged on placement: the check belongs &lt;strong&gt;inside the client's spend controls, on the default path, before the signer runs&lt;/strong&gt; — not in an opt-in hook every developer must remember to register.&lt;/p&gt;

&lt;p&gt;So we built it: &lt;a href="https://github.com/x402-foundation/x402/pull/3920" rel="noopener noreferrer"&gt;PR #3920 to x402-foundation/x402&lt;/a&gt; adds &lt;code&gt;expectedAmount&lt;/code&gt; to &lt;code&gt;x402Client&lt;/code&gt; spend controls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;x402Client&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eip155:8453&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;schemeClient&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setSpendControls&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;maxAmountPerPayment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="c1"&gt;// the cap: maximum exposure&lt;/span&gt;
  &lt;span class="na"&gt;expectedAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$0.01&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;// the expectation: the price you agreed to&lt;/span&gt;
  &lt;span class="na"&gt;expectedAmountTolerance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// optional repricing band (symmetric)&lt;/span&gt;
  &lt;span class="na"&gt;expectedPayTo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0xSeller...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// optional: caller-approved recipient&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What it enforces, pre-signature:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Amount drift&lt;/strong&gt; — explicit expectation or &lt;code&gt;"first-accepted"&lt;/code&gt; anchoring; a mid-session hike (or a bait &lt;em&gt;drop&lt;/em&gt; beyond the band) throws &lt;code&gt;QuoteMismatchError&lt;/code&gt; before the signer is called. The cap alone would have signed it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recipient substitution&lt;/strong&gt; — the first committed &lt;code&gt;payTo&lt;/code&gt; per &lt;code&gt;(resource, scheme, network, asset)&lt;/code&gt; binds the recipient; a payTo-only change at an unchanged amount is rejected. A substituted recipient &lt;em&gt;with&lt;/em&gt; a raised amount cannot re-anchor itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anchor integrity&lt;/strong&gt; — a rejected quote never replaces the accepted anchor; the original price still pays.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fail-closed&lt;/strong&gt; — an offer that &lt;em&gt;cannot&lt;/em&gt; be evaluated (decimal-ledger amount, unknown asset decimals) is rejected explicitly, not silently signed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provenance&lt;/strong&gt; — every rejection carries &lt;code&gt;source: "caller-config" | "quote-ledger"&lt;/code&gt; and &lt;code&gt;field: "amount" | "payTo"&lt;/code&gt;, so integrators can handle it programmatically instead of parsing messages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The thread's reviewer community then did something rare and wonderful: they built an &lt;strong&gt;A1–A9 acceptance matrix&lt;/strong&gt; and cross-checked our PR branch empirically — 12 recorded sessions, signer-call counts, per-field fault injection. Round 1: 8/9 pass, recipient binding (A5) the gap. We fixed it the same night. Round 3 review found a concurrency race (two concurrent first calls could both pass an empty-ledger check) and a silent-pass branch; both closed within hours — payload creation is now serialized per client, and unsupported expectations fail closed.&lt;/p&gt;

&lt;p&gt;That is what open-source review is supposed to look like. 798 tests passing, verified commits, and a sharper design than any of us would have produced alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cap is the floor. The expectation is the check.
&lt;/h2&gt;

&lt;p&gt;One line from the thread deserves to be a motto:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A spending cap limits the maximum exposure; it does not, by itself, verify that the requested amount matches the caller's intended price.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you run agents that pay over x402 today, three things you can do right now:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Set an explicit price expectation&lt;/strong&gt; where you know the price — once #3920 lands, that's one line in spend controls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch your settlement trail&lt;/strong&gt; — compare settled amounts against the seller's median; Agentic Finance Graph offered to re-run the measurement for any specific payTo or threshold.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Put a policy layer in front of the signer&lt;/strong&gt; — allow, ask, or veto &lt;em&gt;before&lt;/em&gt; anything is signed.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Where Boundra fits
&lt;/h2&gt;

&lt;p&gt;Full disclosure: this is the problem our company exists to solve, and the PR is how we think infrastructure should be built — in the open, at the protocol layer, verified by people who don't work for us.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://boundra.io" rel="noopener noreferrer"&gt;Boundra&lt;/a&gt; is the policy decision point for agent payments. The SDK control handles the amount; Boundra handles everything around it: signed user policies (the root of trust is your key, not our database), per-agent scopes with strictest-wins, an ASK path that escalates to a human signature, spend tracking, and a signed &lt;code&gt;boundra.verdict/v1&lt;/code&gt; receipt for every decision — verifiable offline by anyone, issued by the same key that receives our revenue.&lt;/p&gt;

&lt;p&gt;One URL, zero install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"boundra"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://api.boundra.io/mcp"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No signed policy → default-deny. Our evaluation API is itself an x402 merchant: agents pay $0.003 USDC per semantic evaluation, settled for real on Base mainnet (&lt;a href="https://basescan.org/tx/0xf04d3497626c7eea675440eefd037da22ac400ca874daf8e90564ca124eac7e5" rel="noopener noreferrer"&gt;proof&lt;/a&gt;). The business model and the product demo are the same transaction.&lt;/p&gt;

&lt;p&gt;The interface is dying; agents are becoming the buyers. The money they carry deserves the same rigor we'd demand of any counterparty — starting with the simplest question of all:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Is this the price I agreed to?&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Boundra is open source: &lt;a href="https://github.com/gobeyondfj-cmd/boundra" rel="noopener noreferrer"&gt;github.com/gobeyondfj-cmd/boundra&lt;/a&gt;. The replay fixtures, the acceptance-matrix responses, and the SDK PR are all public. Verify everything — that's the point.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>security</category>
      <category>web3</category>
    </item>
  </channel>
</rss>
