T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- src/api/routes.ts:20
- Finding
- Privileged Local API Does Not Authenticate Callers<![CDATA[ ## Vulnerability Details **File Location**: `src/api/routes.ts:20-31`, `src/api/routes.ts:127-176` **Vulnerability Type**: Missing caller authentication on privileged API routes **Risk Level**: Critical ### Vulnerable Code ```ts export async function registerRoutes(app: FastifyInstance) { // Auth gate: block all routes except /health when no API key is configured app.addHook("onRequest", async (req, reply) => { if (req.url === "/health") return; const key = getApiKey(); if (!key) { return reply.code(401).send({ error: "api_key_required", message: "No API key configured. Restart the server to auto-register, or run: bash scripts/setup.sh", docs_url: "https://unbrowse.ai", }); } }); ``` A representative privileged route is: ```ts // POST /v1/auth/steal — extract cookies from Chrome/Firefox SQLite DBs. // No browser launch, Chrome can stay open. Higher rate limit since it's instant. app.post("/v1/auth/steal", { config: { rateLimit: { max: 30, timeWindow: "1 minute" } } }, async (req, reply) => { const { url, chrome_profile, firefox_profile } = req.body as { url: string; chrome_profile?: string; firefox_profile?: string; }; if (!url) return reply.code(400).send({ error: "url required" }); try { const domain = new URL(url).hostname; const result = await extractBrowserAuth(domain, { chromeProfile: chrome_profile, firefoxProfile: firefox_profile, }); return reply.send(result); } catch (err) { return reply.code(500).send({ error: (err as Error).message }); } }); ``` ### Technical Analysis The request hook verifies only whether the server process has an Unbrowse backend API key. It does not authenticate the process or user sending the HTTP request to the local service. Consequently, once the server has registered, every process capable of reaching port 6969 is treated as authorized. This includes rout ...[truncated 1378 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Generate a separate high-entropy local API token and require it on every route other than health checks. - Do not reuse the external marketplace API key as local caller authentication. - Bind permanently to loopback by default and require explicit secure configuration before accepting non-loopback addresses. - Apply stricter authorization to credential extraction, credential storage, mutation execution, and proxy routes. - Reject requests with untrusted browser origins and add CSRF protection where browser clients are supported. - Consider Unix-domain sockets with restrictive filesystem permissions for local-only operation. - Add automated tests proving that unauthenticated callers receive `401` or `403` responses on every privileged endpoint. ]]>
