From 3674b255b2cb2d6ac478d4392cec8c49b5e1220e Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Wed, 17 Jun 2026 20:21:17 -0400 Subject: [PATCH] fix(19): BL-01 enforce LOCAL_SESSION_SECRET length floor in devSessionCookieMiddleware --- apps/api/src/auth/devBypass.ts | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/apps/api/src/auth/devBypass.ts b/apps/api/src/auth/devBypass.ts index d810838..ee71159 100644 --- a/apps/api/src/auth/devBypass.ts +++ b/apps/api/src/auth/devBypass.ts @@ -114,10 +114,36 @@ export function devSessionCookieMiddleware(): MiddlewareHandler { // LOCAL_SESSION_SECRET not set — bypass mode exempts the secret requirement // (assertLocalSessionSecretSet skips when DEV_AUTH_BYPASS=true), but we cannot // issue a cookie without it. Degrade gracefully so devAuthBypass still works. - if (!process.env.LOCAL_SESSION_SECRET) { + const secret = process.env.LOCAL_SESSION_SECRET; + if (!secret) { return async (_c, next) => next(); } + // BL-01: do not treat "present" as "safe". The boot guard's length floor + // (assertLocalSessionSecretSet, >= 32 chars) is SKIPPED in bypass mode, so apply the + // same floor here before minting a real, signature-valid local-session JWT for DEV_USER + // (id=1). A short/forgeable secret must NOT issue a genuine session token. Degrade to a + // no-op so the cookie is never signed with a weak key. + if (secret.length < 32) { + console.warn( + '[devSessionCookieMiddleware] LOCAL_SESSION_SECRET is shorter than 32 characters — ' + + 'refusing to issue a dev local-session cookie. Generate a strong value with ' + + 'node scripts/generate-secrets.mjs.', + ); + return async (_c, next) => next(); + } + + // BL-01: warn loudly if the secret is the well-known dev placeholder. A genuine, + // signature-valid session token minted under this known value is trivially forgeable + // if the same secret ever leaks into a non-bypass environment. + if (secret === 'dev-secret-change-me-0000000000000000') { + console.warn( + '[devSessionCookieMiddleware] LOCAL_SESSION_SECRET is the well-known dev placeholder. ' + + 'This is acceptable ONLY for local dev/CI under DEV_AUTH_BYPASS — never reuse this ' + + 'value in any non-bypass or shared environment.', + ); + } + // Bypass active + secret set: issue a real local-session cookie for DEV_USER // on each request that does not already carry one. return async (c, next) => {