Skip to content

Commit 43d12c7

Browse files
whoabuddyclaude
andauthored
fix(payment-middleware): fail closed when X402_SERVER_ADDRESS missing outside dev (#116)
Closes #112. Two payment middleware sites silently skipped verification when X402_SERVER_ADDRESS was missing, intended as a local-dev convenience: - src/middleware/x402.ts:292 (per-route middleware) - src/index.ts:305 (global middleware) If X402_SERVER_ADDRESS were ever unset in staging or production (bad deploy, secret rotation glitch, env-var migration), all paid endpoints would silently become free with only a warn log. Restrict the skip to ENVIRONMENT === "development". In staging and production, missing config now returns HTTP 503 with code "NOT_CONFIGURED" instead of fail-opening to free. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 9f53811 commit 43d12c7

2 files changed

Lines changed: 27 additions & 6 deletions

File tree

src/index.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,10 +302,20 @@ app.use("*", async (c, next) => {
302302
return next();
303303
}
304304

305-
// Skip if no x402 config (local dev without payment setup)
305+
// Skip is allowed only in local development — staging/production deploys must
306+
// have X402_SERVER_ADDRESS or all paid routes silently become free.
306307
if (!c.env.X402_SERVER_ADDRESS) {
307-
c.var.logger.warn("X402_SERVER_ADDRESS not configured, skipping payment verification");
308-
return next();
308+
if (c.env.ENVIRONMENT === "development") {
309+
c.var.logger.warn("X402_SERVER_ADDRESS not configured (local dev), skipping payment verification");
310+
return next();
311+
}
312+
c.var.logger.error("X402_SERVER_ADDRESS not configured outside local dev — refusing request", {
313+
environment: c.env.ENVIRONMENT,
314+
});
315+
return c.json(
316+
{ error: "x402 misconfiguration", code: "NOT_CONFIGURED" },
317+
503
318+
);
309319
}
310320

311321
// Get tier from endpoint config

src/middleware/x402.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -288,10 +288,21 @@ export function x402Middleware(
288288
return async (c, next) => {
289289
const log = c.var.logger;
290290

291-
// Check if x402 is configured
291+
// Check if x402 is configured. Skip is allowed only in local development —
292+
// staging/production deploys must have X402_SERVER_ADDRESS or all paid routes
293+
// silently become free.
292294
if (!c.env.X402_SERVER_ADDRESS) {
293-
log.warn("X402_SERVER_ADDRESS not configured, skipping payment verification");
294-
return next();
295+
if (c.env.ENVIRONMENT === "development") {
296+
log.warn("X402_SERVER_ADDRESS not configured (local dev), skipping payment verification");
297+
return next();
298+
}
299+
log.error("X402_SERVER_ADDRESS not configured outside local dev — refusing request", {
300+
environment: c.env.ENVIRONMENT,
301+
});
302+
return c.json(
303+
{ error: "x402 misconfiguration", code: "NOT_CONFIGURED" },
304+
503
305+
);
295306
}
296307

297308
// Get token type from header or query

0 commit comments

Comments
 (0)