wevm / wevm/mppx

x402 client: strict `resource.url === response.url` equality rejects valid query-parameterized resources

Open
#906 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
176
Forks
66
Avg merge
1d 1h
Merged PRs (30d)
52

Description

What happened

Using mppx@0.10.1's x402 client directly (mppx/client + mppx/evm/client), a purchase against a real, spec-compliant x402 v2 door failed client-side, before any signature was attempted:

Error: x402 payment-required resource does not match response URL.

Traced to dist/client/internal/protocols/X402.js:

if (response.url && paymentRequired.resource.url !== response.url)
    throw new Error('x402 payment-required resource does not match response URL.');

This does a strict string equality between the resource.url declared inside the 402 envelope and the actual fetched response.url.

Why it breaks a valid case

The door in question requires a query parameter on the paid request (e.g. ?summary=...) — the resource server's own 402 body says as much, and refuses the purchase without it. The server declared resource.url as the bare path (https://example.com/api/buy/thing, no query string), since that's the canonical/logical resource identity. The actual request necessarily carries the required query string, so resource.url !== response.url is guaranteed to be true for any door that requires query input — the check can never pass for that entire class of resource, regardless of whether the request is otherwise perfectly valid.

Spec basis

Per specs/x402-specification-v2.md in x402-foundation/x402, the ResourceInfo.url field is documented only as "URL of the protected resource" — there's no stated requirement that it be byte-identical to the request URL used to fetch it, including query string. Treating it as an exact-match anti-tampering check seems like a reasonable defensive choice, but it's stricter than the spec actually requires, and as written it can't be satisfied by any resource that legitimately needs a query parameter.

Suggested fix

Compare on origin + pathname (ignoring query string), or make the check configurable, rather than full-URL string equality. Happy to open a PR if that's a useful shape for it — wanted to flag the spec-vs-implementation gap first in case there's a reason for the current strictness I'm not seeing.

Repro

Any x402 v2 resource server that (a) requires a query parameter on the paid request and (b) declares its resource.url without that query string (a very natural implementation choice) will reject 100% of purchase attempts made through this client's x402 path. Found this hitting our own store's checkout while testing a native MPP integration.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at dist/client/internal/protocols/X402.js and trace the x402 path used by mppx/client and mppx/evm/client, then compare its URL validation with the ResourceInfo.url wording in specs/x402-specification-v2.md. Done means valid resources whose requests add query parameters are accepted while genuinely mismatched resources remain rejected.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, payments
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.