From be3f37cfdd4b45a2a3dfe672567e1cad8bb87b45 Mon Sep 17 00:00:00 2001 From: Max Mayfield Date: Mon, 2 Mar 2026 20:35:28 +0000 Subject: [PATCH] Fix CRITICAL auth bypass: exact match for login/signup paths startsWith('/api/v1/auth/login') allowed any path with that prefix to bypass authentication (e.g. /api/v1/auth/login-anything). Changed to exact path match with query string stripping. Fixed across all 5 products + shared/auth.ts. --- products/02-iac-drift-detection/saas/src/auth/middleware.ts | 3 ++- products/03-alert-intelligence/src/auth/middleware.ts | 3 ++- products/04-lightweight-idp/src/auth/middleware.ts | 3 ++- products/05-aws-cost-anomaly/src/auth/middleware.ts | 3 ++- products/06-runbook-automation/saas/src/auth/middleware.ts | 3 ++- products/shared/auth.ts | 3 ++- 6 files changed, 12 insertions(+), 6 deletions(-) diff --git a/products/02-iac-drift-detection/saas/src/auth/middleware.ts b/products/02-iac-drift-detection/saas/src/auth/middleware.ts index 74d519f..321df57 100644 --- a/products/02-iac-drift-detection/saas/src/auth/middleware.ts +++ b/products/02-iac-drift-detection/saas/src/auth/middleware.ts @@ -27,7 +27,8 @@ export function registerAuth(app: FastifyInstance, jwtSecret: string, pool: Pool if (req.url === '/health' || req.url === '/version') return; if (req.url.startsWith('/webhooks/')) return; if (req.url.startsWith('/slack/')) return; - if (req.url.startsWith('/api/v1/auth/login') || req.url.startsWith('/api/v1/auth/signup')) return; + const path = req.url.split('?')[0]; + if (path === '/api/v1/auth/login' || path === '/api/v1/auth/signup') return; const apiKey = req.headers['x-api-key'] as string | undefined; const authHeader = req.headers['authorization']; diff --git a/products/03-alert-intelligence/src/auth/middleware.ts b/products/03-alert-intelligence/src/auth/middleware.ts index 74d519f..321df57 100644 --- a/products/03-alert-intelligence/src/auth/middleware.ts +++ b/products/03-alert-intelligence/src/auth/middleware.ts @@ -27,7 +27,8 @@ export function registerAuth(app: FastifyInstance, jwtSecret: string, pool: Pool if (req.url === '/health' || req.url === '/version') return; if (req.url.startsWith('/webhooks/')) return; if (req.url.startsWith('/slack/')) return; - if (req.url.startsWith('/api/v1/auth/login') || req.url.startsWith('/api/v1/auth/signup')) return; + const path = req.url.split('?')[0]; + if (path === '/api/v1/auth/login' || path === '/api/v1/auth/signup') return; const apiKey = req.headers['x-api-key'] as string | undefined; const authHeader = req.headers['authorization']; diff --git a/products/04-lightweight-idp/src/auth/middleware.ts b/products/04-lightweight-idp/src/auth/middleware.ts index 74d519f..321df57 100644 --- a/products/04-lightweight-idp/src/auth/middleware.ts +++ b/products/04-lightweight-idp/src/auth/middleware.ts @@ -27,7 +27,8 @@ export function registerAuth(app: FastifyInstance, jwtSecret: string, pool: Pool if (req.url === '/health' || req.url === '/version') return; if (req.url.startsWith('/webhooks/')) return; if (req.url.startsWith('/slack/')) return; - if (req.url.startsWith('/api/v1/auth/login') || req.url.startsWith('/api/v1/auth/signup')) return; + const path = req.url.split('?')[0]; + if (path === '/api/v1/auth/login' || path === '/api/v1/auth/signup') return; const apiKey = req.headers['x-api-key'] as string | undefined; const authHeader = req.headers['authorization']; diff --git a/products/05-aws-cost-anomaly/src/auth/middleware.ts b/products/05-aws-cost-anomaly/src/auth/middleware.ts index 74d519f..321df57 100644 --- a/products/05-aws-cost-anomaly/src/auth/middleware.ts +++ b/products/05-aws-cost-anomaly/src/auth/middleware.ts @@ -27,7 +27,8 @@ export function registerAuth(app: FastifyInstance, jwtSecret: string, pool: Pool if (req.url === '/health' || req.url === '/version') return; if (req.url.startsWith('/webhooks/')) return; if (req.url.startsWith('/slack/')) return; - if (req.url.startsWith('/api/v1/auth/login') || req.url.startsWith('/api/v1/auth/signup')) return; + const path = req.url.split('?')[0]; + if (path === '/api/v1/auth/login' || path === '/api/v1/auth/signup') return; const apiKey = req.headers['x-api-key'] as string | undefined; const authHeader = req.headers['authorization']; diff --git a/products/06-runbook-automation/saas/src/auth/middleware.ts b/products/06-runbook-automation/saas/src/auth/middleware.ts index 74d519f..321df57 100644 --- a/products/06-runbook-automation/saas/src/auth/middleware.ts +++ b/products/06-runbook-automation/saas/src/auth/middleware.ts @@ -27,7 +27,8 @@ export function registerAuth(app: FastifyInstance, jwtSecret: string, pool: Pool if (req.url === '/health' || req.url === '/version') return; if (req.url.startsWith('/webhooks/')) return; if (req.url.startsWith('/slack/')) return; - if (req.url.startsWith('/api/v1/auth/login') || req.url.startsWith('/api/v1/auth/signup')) return; + const path = req.url.split('?')[0]; + if (path === '/api/v1/auth/login' || path === '/api/v1/auth/signup') return; const apiKey = req.headers['x-api-key'] as string | undefined; const authHeader = req.headers['authorization']; diff --git a/products/shared/auth.ts b/products/shared/auth.ts index 84510bc..2b83366 100644 --- a/products/shared/auth.ts +++ b/products/shared/auth.ts @@ -27,7 +27,8 @@ export function registerAuth(app: FastifyInstance, jwtSecret: string, pool: Pool if (req.url === '/health') return; if (req.url.startsWith('/webhooks/')) return; if (req.url.startsWith('/slack/')) return; - if (req.url.startsWith('/api/v1/auth/login') || req.url.startsWith('/api/v1/auth/signup')) return; + const path = req.url.split('?')[0]; + if (path === '/api/v1/auth/login' || path === '/api/v1/auth/signup') return; const apiKey = req.headers['x-api-key'] as string | undefined; const authHeader = req.headers['authorization'];