T05 · Unauthorized Access and Privilege Escalation
- Location
bridge/server.py:81- Finding
Authentication Is Deliberately Fail-Open
- Content
View full analysis
str: auth = request.headers.get("authorization", "") token = auth.replace("Bearer ", "").strip() # Also check x-api-key header (ElevenLabs sometimes uses this) x_api_key = request.headers.get("x-api-key", "") if not token and x_api_key: token = x_api_key.strip() if token and token != LLM_BRIDGE_TOKEN: logger.warning(f"Invalid auth token (accepting anyway): {token[:15]}...") return token or "anonymous" ``` The result is called but never checked: ```python raw_body = await request.body() body_str = raw_body.decode("utf-8", errors="replace") await verify_token(request) # Parse body body = {} ``` ### Technical Analysis `verify_token()` accepts all three authentication states: 1. A valid bridge token. 2. An invalid bridge token. 3. No token at all, represented as `"anonymous"`. The explicit `"accepting anyway"` branch makes the documented Bearer-token control nonfunctional. The caller does not inspect the returned identity or reject anonymous access. Because the bridge invokes Anthropic and BlueColumn with credentials held by the server, remote clients effectively gain indirect use of those privileged credentials even though the credentials themselves are not returned. The warning also logs the first 15 characters of an attacker-supplied token. Token values should not be logged because users may accidentally submit real credentials for another service. ### Attack Path 1. The operator exposes port 8013 through the documented Cloudflare or ngrok tunnel. 2. An attacker sends `POST /v1/chat/completions` with no `Authorization` header, or with any arbitrary Bearer token. 3. `verify_token()` returns `"anonymous"` or logs the mi ...[truncated 911 chars]- Remediation
View remediation
None: auth = request.headers.get("authorization", "") token = auth.removeprefix("Bearer ").strip() if not token: token = request.headers.get("x-api-key", "").strip() if not LLM_BRIDGE_TOKEN or not secrets.compare_digest(token, LLM_BRIDGE_TOKEN): raise HTTPException(status_code=401, detail="Invalid authentication") ``` ]]>
