Agent payment operations
x402 client spend limits: check your version and add a guard
Published October 27, 2026 · SpendPreflight · AI-assisted; primary sources checked on this date.
A server’s payment request is an offer, not your spending policy. Check the exact packages your application loads, keep their security updates current, and enforce the amount and recipient you intended before the signing step.
What was confirmed
V12’s October 22 report describes three critical findings: an older Solana verifier accepted an approval as a transfer, an automatic login wrapper failed to bind a signature to the contacted website, and default client setup lacked a spending budget. V12 says the critical fixes were completed by August 20. This guide does not claim a new October zero-day, exploitation of your deployment, or an independently reproduced attack.
The March 6 maintainer advisory, GHSA-qr2g-p6q7-w82m, is a separate Solana facilitator issue. It lists patched releases of @x402/svm >=2.6.0, Python x402 >=2.3.0, and Go x402 >=2.5.0. Its affected role and release numbers must not be reused as a blanket V12 client-fix matrix. GitLab’s npm, Python, and Go indexes point to that older advisory.
Five Attacks on x402 Agentic Payment Protocol is a separate May preprint about payment workflow weaknesses. It is useful threat-model context, not evidence that a particular current seller or SDK version is vulnerable.
1. Inventory what is actually running
# Read installed versions; these commands do not make a payment.
npm ls @x402/core @x402/fetch @x402/axios @x402/svm @x402/extensions spendpreflight
python -m pip show x402
go list -m all
Use the commands for your application’s language. Compare the deployed lockfile and container with development; a package range in a manifest does not establish the version loaded at runtime. Review client, extension, server and facilitator dependencies separately. A hosted facilitator’s version cannot usually be proved from your own lockfile.
2. Read the matching release notes and configuration
The pinned TypeScript core changelog records default spend controls in 2.23.0: recognized USD-pegged assets and a $1 per-payment cap. It also records SIWx origin binding in that release. The pinned Python changelog records its default spend controls in 2.20.0. These are package-specific release-note observations, not a promise that those releases fix every known issue.
Review configuration that disables or broadens those defaults, including spendControls: false, Python spend_controls=False, and permissive asset options. A per-payment ceiling does not establish an application-wide daily budget. Upgrade through your normal dependency process, read breaking changes, pin the resulting lockfile and exercise the actual configured client with offline fixtures.
3. Put your own decision before signing
The free spendpreflight-js guard attaches to an existing official x402 client. Here is a local-only policy example; client is your already-configured client. Choose limits for your application rather than copying these sample values into a funded agent without review.
import { guard } from "spendpreflight";
guard(client, {
remote: false,
rules: {
maxPerPaymentUsd: 0.10,
holdAboveUsd: 0.05,
dailyCapUsd: 1,
allowedNetworks: ["eip155:8453"],
usdcOnly: true,
},
onHold: async () => false,
});
// Attach before your payment-capable wrapper makes its first request.
This configuration does no remote screening. Holds are denied in the example; an approval workflow must explicitly decide whether to proceed. Use recipient/domain allowlists when your workflow knows its destinations. For changing quotes, compare against the expected purchase amount too: a charge can be within a broad cap and still exceed the price you intended.
The guard’s daily reservation is in memory, per guard/process and UTC day. It is not durable across restarts, coordinated across multiple workers, or a ledger of settled payments. Failed or abandoned authorizations retain their reservation until the next UTC day. A fleet needs an external shared budget and signer restrictions. Local policy does not repair a vulnerable facilitator or validate every login-signature extension.
4. Check refusal behavior without spending
Use local fixtures and a throwaway signer to check an excessive quote, a disallowed network/asset, a blocked recipient and simultaneous requests near the budget. Assert that denied requests never reach the signer. Re-run after dependency or policy changes. Do not send forged or replayed payment headers to other sellers, and do not fund a wallet merely to test this guide.
Checks for the seller side
The free x402 Lint and GitHub Action inspect unpaid public endpoint behavior and report their limits. They cannot prove the version or spending policy inside a buyer, successful settlement, replay protection, or freedom from vulnerabilities. Use them alongside dependency review and your own controlled tests. See also the seller checklist and local spend-policy overview.
Frequently asked questions
Does a valid 402 authorize the amount?
No. Parsing an offer establishes its format, not permission to spend. Your application and signer must enforce the intended purchase and budget.
Does upgrading remove the need for a budget?
No. Review current release notes and configured defaults, then enforce your own per-payment and shared cumulative limits. No version number proves the whole deployment safe.
Does SpendPreflight hold or move funds?
No. The guard signals allow, hold or block before your client signs. Optional remote checks are separate from the local-only example above.
14 days free for founding sellers
The first 10 eligible Basic registrations can receive 14 days of monitoring without a wallet or payment, subject to availability and confirmed alert email. After the free period, Basic is 9 USDC for a manually renewed 31-day period.
Check founding availability