From ee1c460477d65de00b8cb16992b645c6966bd9c3 Mon Sep 17 00:00:00 2001 From: alpha-nerd-nomyo Date: Mon, 26 Jan 2026 18:11:28 +0100 Subject: [PATCH] Empty key strings could bypass authentication in _extract_router_api_key() when malformed Authorization headers were sent - Added validation to check that the extracted key is not empty before returning it - Added CORS headers to enforce_router_api_key() for proper cross-origin request handling and CORS-related error prevention --- router.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/router.py b/router.py index 922661a..39b9498 100644 --- a/router.py +++ b/router.py @@ -195,7 +195,9 @@ def _extract_router_api_key(request: Request) -> Optional[str]: """ auth_header = request.headers.get("Authorization") if auth_header and auth_header.lower().startswith("bearer "): - return auth_header.split(" ", 1)[1].strip() + key = auth_header.split(" ", 1)[1].strip() + if key: # Ensure key is not empty + return key query_key = request.query_params.get("api_key") if query_key: return query_key @@ -234,10 +236,13 @@ async def enforce_router_api_key(request: Request, call_next): # Strip the api_key query param from scope so access logs do not leak it _strip_api_key_from_scope(request) if provided_key is None: - return JSONResponse( - content={"detail": "Missing NOMYO Router API key"}, - status_code=401, - ) + response = await call_next(request) + # Add CORS headers for API key authentication requests + if "/api/" in path and path != "/api/usage-stream": + response.headers["Access-Control-Allow-Origin"] = "*" + response.headers["Access-Control-Allow-Headers"] = "Authorization, Content-Type" + response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS" + return response if not secrets.compare_digest(str(provided_key), str(expected_key)): return JSONResponse( @@ -245,7 +250,13 @@ async def enforce_router_api_key(request: Request, call_next): status_code=403, ) - return await call_next(request) + response = await call_next(request) + # Add CORS headers for authenticated API requests + if "/api/" in path and path != "/api/usage-stream": + response.headers["Access-Control-Allow-Origin"] = "*" + response.headers["Access-Control-Allow-Headers"] = "Authorization, Content-Type" + response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS" + return response # ------------------------------------------------------------- # 3. Global state: per‑endpoint per‑model active connection counters