Hi, I noticed a possible verify-only payment gate in the SDK HTTP wrappers.
In packages/sdk/src/serve.ts, the helper posts to the facilitator /verify endpoint:
145: async function verifyWithFacilitator(
146: paymentPayload: Record<string, unknown>,
147: paymentRequirements: Record<string, unknown>,
148: facilitatorUrl: string,
150: const response = await fetch(`${facilitatorUrl}/verify`, {
153: body: JSON.stringify({
154: x402Version: paymentPayload.x402Version ?? 1,
155: paymentPayload,
156: paymentRequirements,
157: }),
165: return (await response.json()) as {
166: isValid: boolean
The Express wrapper runs the handler after isValid:
259: try {
260: const result = await verifyWithFacilitator(payload, requirements, facilitatorUrl)
261: if (!result.isValid) {
262: res.status(402).json({
267: }
275:
276: return handler(req, res, next)
The Hono wrapper does the same:
352: try {
353: const result = await verifyWithFacilitator(payload, requirements, facilitatorUrl)
354: if (!result.isValid) {
355: return c.json(
360: 402,
361: )
362: }
372:
373: return handler(c, next)
And the Next-style wrapper also runs the handler after verify:
458: try {
459: const result = await verifyWithFacilitator(payload, requirements, facilitatorUrl)
460: if (!result.isValid) {
461: return new Response(
467: ) as unknown as T
468: }
478:
479: return handler(req)
The API documentation describes /facilitator/verify as a soft gate rather than settlement:
1062: /facilitator/verify:
1065: operationId: verifyPayment
1066: summary: Verify an x402 payment signature
1067: description: |
1068: Checks that a payment signature is valid without settling on-chain.
1069: Use this for soft-gating - verify intent before committing.
1070: Does not prevent replay (use `/facilitator/settle` for that).
The effective wrapper lifecycle appears to be:
payment payload -> /verify isValid -> protected HTTP handler
I did not see a /settle call or replay/nonce consumption in these SDK wrapper paths before the protected handler runs.
A safer design would either settle before executing non-reversible handlers, or clearly document these wrappers as verify-only soft gates and provide a settle-before-handler variant. I am reporting this as a potential issue rather than a confirmed exploit, since other parts of the repository may use stronger merchant flows.
Hi, I noticed a possible verify-only payment gate in the SDK HTTP wrappers.
In
packages/sdk/src/serve.ts, the helper posts to the facilitator/verifyendpoint:The Express wrapper runs the handler after
isValid:The Hono wrapper does the same:
And the Next-style wrapper also runs the handler after verify:
The API documentation describes
/facilitator/verifyas a soft gate rather than settlement:The effective wrapper lifecycle appears to be:
I did not see a
/settlecall or replay/nonce consumption in these SDK wrapper paths before the protected handler runs.A safer design would either settle before executing non-reversible handlers, or clearly document these wrappers as verify-only soft gates and provide a settle-before-handler variant. I am reporting this as a potential issue rather than a confirmed exploit, since other parts of the repository may use stronger merchant flows.