← Blog
October 23, 2026 · 9 min

Agentic week: sixty merged fixes, no release

x402 merged 60 pull requests between 16 and 23 October. It published none of them. The fixes include a settlement override that could exceed the authorized amount, a reflected XSS in the HTML paywalls, a CORS preflight answered with a 402, and a canonicalizer that disagreed with RFC 8785. The Linux Foundation also named an executive director for the x402 Foundation.

We counted merges in x402-foundation/x402 by mergedAt from 16 October 00:00 UTC. The previous roundup counted eight for its window, so the pace changed. The release pace did not. @x402/core 2.28.0 on npm is dated 29 September, Python x402 2.25.0 on PyPI the same day, and the newest Python tag is [email protected]. Every fix below is in main and in none of those artifacts at the time of writing.

1. The foundation gets an executive director

The Linux Foundation appointed Michael Hursta executive director of the x402 Foundation. The release is dated 1 October, and the October newsletter of 21 October repeats it. It cites 50+ member organizations and more than 20 years in payments, including payment acceptance for North America at Amazon, an enterprise payments practice at PwC and a decade at First Data.

The quote worth keeping: "x402 gives the industry an opportunity to build that next layer as open infrastructure rather than another proprietary payment system." Nothing in the release changes the wire format. It does change who answers when a proposal stalls, which matters for the XP process we covered earlier today.

2. One ceiling, three SDKs, a bot that counts the drift

Issue #3876, "SDK drift detected", was opened on 22 October. It lists five changes that landed in TypeScript and are missing in Go and Python.

The sharpest is the settlement override. In TypeScript, resolveSettlementOverrideAmount() accepted raw, percent and dollar overrides without checking them against PaymentRequirements.amount, although its own JSDoc says the resolved amount must be at most the authorized maximum. PR #3338 added the check and merged on 22 October. The Python port, #3877, shows what the old code did: a 500% override of 1,000,000 atomic units returned 5,000,000, and a $1000000 override at 7 decimals returned 10,000,000,000,000. The Go port, #3881, now returns invalid_settlement_override instead. Both ports merged on 23 October.

This is the guard the upto scheme depends on. The buyer signs a maximum, the seller settles for less. The ceiling is the seller-side check that the settled amount never exceeds what the buyer signed.

Three more items in the list are in the same state:

PhilBot402 authored eight of the 60 merges, more than any other account, and its PR text carries an "AI disclosure" line naming the maintainer who operates it. The drift report and the ports form a loop: a machine finds the gap, a machine closes it, a human merges. It works only while the TypeScript fix is the reference. A bug that TypeScript never had gets no report.

3. The browser path: a preflight and a paywall page

Two merges concern browsers, and both touch what we measured in the CORS and preflight audit.

OPTIONS no longer costs money. PR #3738 (merged 22 October) fixes route matching. A route keyed without a method, or a single route config, compiles to the verb *, and that matched every method including OPTIONS. The middleware answered the browser's preflight with a 402, the browser failed the preflight, and the paid request was never sent. Routes keyed "POST /api/data" were unaffected. Now * skips OPTIONS in TypeScript, Python and Go, while an explicit "OPTIONS /path" route still requires payment. The legacy v1 packages keep the bug on purpose, since the maintainers froze them. The companion problem, issue #3722 on Access-Control-Expose-Headers, is still open with 17 comments.

The paywall page was injectable. Issue #3852 reported reflected XSS in the HTML paywall: configuration went into an inline script through JSON.stringify with < left intact, so request-derived values, such as the URL path or the Host header, could close the script element. PR #3855 merged three days later and applies script-safe serialization to the EVM, SVM, AVM and legacy v1 paywalls. Its own description says the regeneration "does not apply the serializer fix to the Go or Python generators". Those templates were regenerated from source, not patched.

4. Two signature details that break interoperability

PR #3822 fixes EIP-3009 settlement for wallets that write v as 0 or 1. viem's parseSignature returns yParity and no v when a 65-byte signature ends in 0x00 or 0x01, and the facilitator passed yParity through as v. Tokens that accept only 27 or 28, such as USDC's FiatToken, rejected valid payments at simulation or at settlement. The fix passes yParity + 27.

PR #3700 makes the offer-receipt canonicalize function conform to RFC 8785. Control characters were escaped as \u00XX instead of \b \t \n \f \r, lone surrogates were accepted, a top-level undefined became null, and sparse array holes produced invalid JSON. Signed bytes could therefore differ from any other RFC 8785 implementation for a string containing a tab. The PR notes that verification is unaffected because it checks the JWS bytes as issued. The break is for a second signer or an independent verifier, which is the case we described in the receipts audit.

What it means for LLM4Agents

The release gap is the finding. Any gateway that pins @x402/core 2.28.0 runs the pre-fix behavior for all of the above, and the project that wrote the fixes has not shipped them. Reading main tells us what is coming. It does not change what we run.

Exposure by item. The override ceiling matters wherever we settle below a signed maximum, as with a metered call priced against a quote. The ceiling keeps a bug in our accounting from becoming an over-charge. The 402 body change helps agents that read JSON, because they get a reason without decoding a header. The preflight fix removes a failure mode for browser-based buyers. The XSS matters only if a route can return the HTML paywall. The v and RFC 8785 fixes matter for interoperability with wallets and with independent receipt verifiers.

The drift issue shows a second risk. A multi-language stack behaves differently per SDK for days. A buyer on Python and a buyer on TypeScript can get different answers to the same malformed network string.

Staying on the frontier

First, make the ceiling ours. Enforce "settled amount at most quoted maximum" in our own settlement code, with a test that sends 500% and a dollar override. Do not wait for the SDK release to carry it.

Second, test the shipped artifact, not main. Add a CI job that installs the pinned release and runs the cases from this week: OPTIONS on a method-less route, a v of 0 and 1, a tab in a receipt payload, eip155:84532:extra as a network. Each failing case is a known gap with a PR number.

Third, decide the pin policy. Three and a half weeks without a tag is long enough to choose between a pinned release and a reviewed commit SHA for the fixes we need. Write down the criteria, then re-check the npm and PyPI dates every Friday.

Fourth, return a reason in our own 402 bodies. Put a stable error code in the JSON body of every rejection, next to the header. Agents read the body first.

Fifth, audit HTML responses. List every route that can return a page to a browser and confirm none embeds request-derived data in an inline script.

Pay per call, in stablecoins, over an OpenAI-compatible API

Register an agent, fund it, and start routing. No subscription, no monthly minimum.

Register an agent