DEV Community

Ryan Gillespie
Ryan Gillespie

Posted on

Five ways an x402 paid endpoint can serve content it wasn't paid for, and a CI check for each

x402 turns HTTP 402 into a real payment flow: your server answers 402 with payment requirements, the client pays, and a facilitator verifies and settles. The happy path is easy. Money is lost in the unhappy paths. Here are five I test for, and how to check your own server in one CI step.

1. A /settle call that times out. If your middleware treats "no answer" as "probably fine", anyone can get content by making settlement slow. Fix: serve only after a well-formed success: true.

2. A 503 with a success body. Proxies return error pages, and sometimes success-looking bodies with a 5xx status. Fix: check the status code before you read the body, and keep the payment retryable.

3. settlement_pending treated as paid. In x402 V2 (ยง9), settlement_pending is non-terminal: the transaction may still fail. Fix: don't serve until it's final; keep the transaction and reconcile.

4. The same payment presented twice. Fix: the facilitator must answer duplicate_settlement for a payload it already settled, and your check-and-insert must be atomic.

5. A reused memo in a new transaction. On Solana devnet the reference facilitator dedupes by transaction, not by memo: two different transactions with the same memo both settled. If your app maps one memo to one purchase, you must enforce single use yourself. (Devnet transactions and hashes: https://atsp-protocol.github.io/x402-conformance/)

Check your server. x402-conformance is an open-source (Apache-2.0) GitHub Action that puts a facilitator double in front of your server and requests your paid route under each fault:

- uses: atsp-protocol/x402-conformance@v1
  id: x402
  with:
    resource-url: http://127.0.0.1:4020/paid
    start: node server.js   # your server must use X402_FACILITATOR_URL
    fail-on-error: false
- uses: github/codeql-action/upload-sarif@v3
  if: always()
  with:
    sarif_file: ${{ steps.x402.outputs.sarif }}
    category: x402-conformance
Enter fullscreen mode Exit fullscreen mode

Failures show up in your repo's Security tab, and each one links to a "what failed and how to fix it" entry in the fix guide. There's a JUnit report too. For facilitators, live mode only sends GET /supported. No install needed: pipx run --spec "git+https://github.com/atsp-protocol/x402-conformance@v1" x402conf offline.

It's experimental and Solana-first; issues and check proposals are welcome: https://github.com/atsp-protocol/x402-conformance

Top comments (0)