# Older x402 clients let the server pick the amount. What to check on Celo

**URL:** <https://forum.celo.org/t/older-x402-clients-let-the-server-pick-the-amount-what-to-check-on-celo/13958>\
**Category:** Developers\
**Created:** [October 29, 2026, 7:43am UTC](https://forum.celo.org/t/older-x402-clients-let-the-server-pick-the-amount-what-to-check-on-celo/13958 "2026-10-29T07:43:12Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Zealynx](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.celo.org/zealynx/32/12323_2.png) [@Zealynx](https://forum.celo.org/u/Zealynx)\
**Post date:** [October 29, 2026, 7:43am UTC](https://forum.celo.org/t/older-x402-clients-let-the-server-pick-the-amount-what-to-check-on-celo/13958/1 "2026-10-29T07:43:12Z")

</div>

V12 [published a review](https://v12.sh/blog/x402) of the x402 SDKs on 22 October: 25 findings, three of them critical. All three were fixed in the releases of 18 August, so this is not about anything open. I’m writing it up here because a lot of the agents being built on Celo right now pay with x402, and a couple of things about those fixes are easy to miss.

The first one is that nobody published an advisory for them. The x402 repo has two older advisories (August 2025 for the v1 packages, March 2026 for `@x402/svm` below 2.6.0), but nothing for the August 2026 fixes. So a project pinned to `@x402/fetch` 2.22.0 still gets a clean `npm audit`.

### What changed in the client

Before 2.23.0, the default client took the first payment option in the 402 response and signed it. The server chose the amount, the token, the recipient and the network. If your agent signs on its own, a hostile or compromised endpoint could ask for the whole USDC balance and get a valid authorization for it.

Since 2.23.0 in TypeScript and Go (2.20.0 in Python) the client has `spendControls`. By default it only pays tokens from the SDK’s default asset table, and at most $1 per payment.

On Celo mainnet that table has [three tokens](https://github.com/x402-foundation/x402/blob/e4a086819f419e9395acbbdc1679fe6627029ff7/typescript/packages/mechanisms/evm/src/defaultAssets.ts#L259-L281): USDC, USDT and USAT. USDm, COPm and the other Mento stables are not in it, and neither is any other local token. If a server asks for one of those, a default client refuses, and the error tells you how to get past it: add an `allowedAssets` entry, set `allowedAssets: true`, or set `spendControls: false`.

### The easy fixes remove the cap

`spendControls: false` is the old behaviour again. `allowedAssets: true` lets any token through, and the $1 cap then only applies to USDC, USDT and USAT, so every other token is uncapped. An `allowedAssets` entry without `maxAmountPerPayment` is also uncapped. You can read all of it in [the client](https://github.com/x402-foundation/x402/blob/e4a086819f419e9395acbbdc1679fe6627029ff7/typescript/packages/core/src/client/x402Client.ts#L155-L192).

So if your agent pays in a Mento stable, what you want is a list entry with a cap. The cap is in atomic units, not dollars, and USDm and COPm have 18 decimals where USDC has 6. The SDK’s own example uses `"2000000"`, which is 2 USDC but 0.000000000002 USDm. Copy that for a Mento token and every payment gets rejected, which is exactly when people reach for `spendControls: false`. Read `decimals()` from the token and do the math once.

The cap is also per payment. A server can still ask for $1 a hundred times, and spend controls don’t look at `payTo`. If your agent only pays a few known services, keep only those recipients with `registerPolicy`, and keep a running total in an `onBeforePaymentCreation` hook, which can abort the payment.

### The other two fixes

If your agent signs in with SIWx (Sign-In-With-X), versions before 2.23.0 signed whatever `domain` and `uri` the 402 response gave. A server could forward a login challenge from another site and log in there as your wallet. Now `createSIWxPayload` takes the final URL of the 402 response and refuses to sign when the origin doesn’t match. `@x402/fetch` and `@x402/axios` pass that URL for you. If you call `createSIWxPayload` yourself, you have to pass it.

The third one was in the TypeScript Solana facilitator, which accepted an `ApproveChecked` instruction as a payment (it differs from `TransferChecked` in one byte). Fixed in `@x402/svm` 2.23.0. On Celo it only matters if your facilitator also settles Solana.

On the server side there’s one more worth knowing. `@x402/core` 2.27.0 (22 September) fixed paid routes that could be reached without paying by encoding the slash, like `/api%2Fpremium`, when the framework routed on the decoded path and the payment middleware only checked the raw one.

### What I’d check this week

1. Your versions: `npm ls @x402/core @x402/fetch @x402/evm`, or `x402` in pip, or the Go module. Clients at 2.23.0 or later (Python 2.20.0), servers at 2.27.0 or later. The latest is 2.29.0, out on 28 October.
2. Search your code for `spendControls: false` and `allowedAssets: true`.
3. For every Mento or local token you allow, a cap with the right decimals.
4. If the agent pays a fixed set of services, pinned recipients and a total budget.

For the agent builders here: which tokens do your agents actually pay in? And did the $1 default break anything for you when you upgraded?
