Security considerations
x402 moves money on every request. Security mistakes here cost real funds. This page outlines the threat model and practical mitigations.
Trust boundaries
Section titled “Trust boundaries”Client (untrusted) ──► Your Server (trusted) ──► Facilitator (trusted for settlement) ──► Chain (trustless / consensus)- Never trust the client to report payment success. The server must verify via the facilitator or on-chain before releasing resources.
- The facilitator is a trusted third party for verification and settlement. Choose one with a security track record and audit history.
- Your server is the policy layer: it decides what requires payment, how much, and whether verification is sufficient to release data.
Replay protection
Section titled “Replay protection”EIP-3009 transferWithAuthorization uses a random nonce (32 bytes). Once the facilitator submits the transfer on-chain, that nonce is marked as used in the token contract — replaying the same signature reverts.
Your responsibilities:
- Generate nonces with
crypto.getRandomValues, never incrementally. - Don’t cache or log full payment signatures in a way that could be exfiltrated and replayed before settlement.
- If your server receives the same
payment-signaturetwice (e.g. client retry), the facilitator’ssettlecall should be idempotent or return an error. Handle both cases.
Authorization expiry
Section titled “Authorization expiry”Set validBefore as tight as practical. For a single API request, 5–15 minutes is reasonable. One hour is the upper bound for interactive flows. Long-lived authorizations increase the window for front-running.
validAfter can be 0 (immediately valid) for typical request-response flows.
Signature front-running
Section titled “Signature front-running”If the payment-signature header is intercepted in transit (e.g. no TLS), an attacker could submit the authorization before your server does. Mitigations:
- Always use HTTPS in production.
- The
tofield in the authorization is fixed to the merchant address — an attacker can’t redirect funds, but they could cause settlement to happen before your server calls the facilitator (wasting your user’s authorization). - Some facilitators support
receiveWithAuthorizationwhich restricts the caller to thetoaddress, preventing third-party submission.
Amount manipulation
Section titled “Amount manipulation”The client constructs the payment based on the 402 response body. A malicious client could sign a lower amount. Your server must not trust the amount in the payment-signature — the facilitator’s verify step should reject mismatches. Confirm your facilitator validates amount ≥ maxAmountRequired.
Facilitator trust
Section titled “Facilitator trust”You’re trusting the facilitator to:
- Honestly verify that the signature is valid and the amount is correct.
- Actually settle the transfer on-chain to your
payToaddress. - Not front-run or redirect funds.
Mitigations:
- Use established facilitators (Coinbase CDP, thirdweb) with public APIs and audit trails.
- Verify settlement independently: check your
payTobalance or query the chain for thetxHashthe facilitator returns. - Log the
txHashand periodically reconcile against on-chain records.
Server-side secrets
Section titled “Server-side secrets”| Secret | Where it lives | Exposure risk |
|---|---|---|
facilitatorUrl | Server env | If leaked, attacker could call verify/settle directly (low risk — they’d need valid signatures) |
payTo address | Server config + 402 body | Public by design (clients need it to sign) |
TallyPay apiKey (tp_live_…) | Server + client env | If leaked, attacker can send fake trace events. Not a payment risk, but pollutes your dashboard data |
| Wallet private key | Never on your server | If you’re self-hosting a facilitator, guard this with HSM / KMS |
Logging
Section titled “Logging”- Never log raw
payment-signaturevalues. They contain signed authorizations that may not yet be settled. - Do log
traceId,txHash, facilitator response codes, and your own request IDs. - Treat facilitator responses as untrusted input when constructing error messages for clients.
Production checklist
Section titled “Production checklist”- HTTPS everywhere (mixed content breaks wallet libraries)
- Separate testnet and mainnet facilitator URLs,
payToaddresses, and TallyPay API keys -
validBeforeset to < 15 minutes for standard flows - Reconciliation: periodically verify
txHashvalues against on-chain state - Rate limiting on your 402 endpoints to prevent abuse (repeated 402s are cheap for an attacker)
- CORS configured to your own origins only (don’t wildcard in production)
- Error responses never leak facilitator internals or raw signatures