A AegiFlow
HIGHCVSS 8.6EPSS 0.6%

CVE-2026-55638

9router: Unauthenticated LLM proxy access via /codex rewrite authorization bypass

Published
2026-08-28
Modified
2026-08-28
EPSS percentile
47%
Aliases
GHSA-8gmq-j984-vp4r
Sources
github-advisory

Summary

## Summary 9router exposes an OpenAI/Anthropic-compatible LLM proxy. Remote access to this proxy is intended to be protected by an API-key check in the Next.js middleware. However, 9router also defines a rewrite that maps `/codex/*` to the backend LLM endpoint `/api/v1/responses`. The middleware authorization decision is made on the incoming request path before the rewrite is applied. Because `/codex` is not included in the middleware's protected LLM API prefix list, requests to `/codex/*` bypass the API-key gate and are later rewritten to the same backend used by `/api/v1/responses`. As a result, an unauthenticated remote attacker can access the LLM proxy through `/codex/*` and cause the server to make upstream provider calls using the operator-stored LLM provider credentials. ## Details | Component | File | Note | | ----------------------------- | ----------------------------------- | ------------------------------------------------------------------------- | | Middleware authorization gate | `src/dashboardGuard.js` | Protects `/v1`, `/v1beta`, `/api/v1`, and `/api/v1beta`, but not `/codex` | | Rewrite configuration | `next.config.mjs` | Rewrites `/codex/:path*` to `/api/v1/responses` | | LLM backend route | `src/app/api/v1/responses/route.js` | Dispatches rewritten requests to the LLM handler | | Chat handler | `src/sse/handlers/chat.js` | Uses operator-stored provider credentials for upstream calls | Tested version: | Version / Commit | Runtime | Status | | ------------------------------------------------------------ | ---------------- | -------- | | `v0.4.80`, commit `23da7b1fe3bb8edd2bdbdb63fbbb15a476b02c56` | Next.js `16.2.9` | Affected | ### Root Cause The middleware classifies requests by the original incoming pathname. The protected public LLM API prefixes are: ```js PUBLIC_PREFIXES = ["/v1", "/v1beta", "/api/v1", "/api/v1beta"]; ``` Because `/codex` is not included in this list, a request such as `/codex/x` does not enter the LLM API authorization branch and falls through to: ```js return NextResponse.next(); ``` The rewrite configuration then maps the allowed request to the protected backend route: ```js { source: "/codex/:path*", destination: "/api/v1/responses" } ``` The backend route reaches the same handler used by the canonical LLM endpoint: ```js return await handleChat(request); ``` The handler then processes the request and performs the upstream LLM provider call. In the tested configuration, the handler does not repeat the same middleware API-key gate for remote callers, so the rewritten request is served after bypassing the intended authorization check. ## PoC The following requests use the same target server and the same remote-style `Host` header. The only meaningful difference is the request path. ### Case 01 — Protected canonical endpoint rejects unauthenticated access ```http POST /api/v1/responses HTTP/1.1 Host: evil.attacker.com Content-Type: application/json Content-Length: 156 {"model":"fakeoai/x","input":"NINEROUTER_CODEX_AUTH_BYPASS_MARKER hello","messages":[{"role":"user","content":"NINEROUTER_CODEX_AUTH_BYPASS_MARKER hello"}]} ``` Observed result: ```http HTTP/1.1 401 Unauthorized ``` This confirms that the canonical `/api/v1/responses` path is protected by the intended API-key gate. ### Case 02 — Rewritten `/codex/*` path bypasses the API-key gate ```http POST /codex/x HTTP/1.1 Host: evil.attacker.com Content-Type: application/json Content-Length: 156 {"model":"fakeoai/x","input":"NINEROUTER_CODEX_AUTH_BYPASS_MARKER hello","messages":[{"role":"user","content":"NINEROUTER_CODEX_AUTH_BYPASS_MARKER hello"}]} ``` Observed result: ```http HTTP/1.1 200 OK

Affected packages

EcosystemPackageAffected versionsFixed versions
npm9router0.5.2

Remediation: Upgrade to 0.5.2 or later.

References

Includes data from the GitHub Advisory Database, licensed under CC-BY 4.0.

CVE® is a registered trademark of The MITRE Corporation. CVE content reproduced under the CVE Terms of Use; copyright designation © MITRE.

EPSS scores provided by the FIRST.org Exploit Prediction Scoring System.