Open actionable advisories and recorded vendor fixes. This public package view has no inventory attached and cannot establish whether your deployment is affected. A vendor fix never resolves your finding; verify your installed version and the source guidance.
Open advisories
13 actionable advisories, newest first. Withdrawn advisories and news are excluded. Coverage is partial.
The PATCH /api/settings endpoint writes the entire request body to persistent settings without a field whitelist. An authenticated user can set security-critical fields that are not meant to be modifiable here — notably requireLogin. Setting requireLogin: false disables authentication for the whole application, exposing all protected routes (e.g. /api/keys, /api/providers) to unauthenticated access. Details Root cause is unfiltered mass assignment (CWE-915): - src/app/api/settings/route.js (PATCH handler) parses the body and passes it to updateSettings(body), with special handling only for newPassword and oidcClientSecret. All other fields pass through. - src/lib/db/repos/settingsRepo.js — updateSettings does next = { ...current, ...updates }, so any key in the body overwrites stored settings, including requireLogin, tunnelDashboardAccess, authMode. - src/dashboardGuard.js — isAuthenticated returns true whenever settings.requireLogin === false, bypassing auth on all protected…
Recommended action: Upgrade to 0.5.4 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
The Kiro API-key validation endpoint builds an upstream URL using a user-controlled region value. By supplying a crafted region such as kiro-canary.local:8443#, an authenticated attacker can cause 9router to send the Kiro validation request to an attacker-controlled host under the constructed codewhisperer.<region hostname. The request forwards the submitted Kiro API key as an Authorization: Bearer header. Details - Affected version / commit: 9router v0.5.2 @ 5da508a. - Endpoint: POST /api/oauth/kiro/api-key. - Correct runtime payload: region: "kiro-canary.local:8443#". - Do not use the old @host payload (region: "@kiro-canary.local:8443#"); it is blocked by Node/undici fetch() because it creates URL credentials ("Request cannot be constructed from a URL that includes credentials"). - Constructed upstream host becomes: codewhisperer.kiro-canary.local:8443 (the turns the trailing .amazonaws.com into a URL fragment). - HTTPS canary captured: Authorization: Bearer…
Recommended action: Upgrade to 0.5.6 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
9router validates image URLs by resolving the host before fetching, but the later server-side fetch performs a separate DNS resolution. An attacker-controlled DNS name can resolve to a public IP during validation and then rebind to an internal Docker/private IP during the fetch. This allows the server-side image prefetch to reach internal-only HTTP services (SSRF). Details - Affected version / commit: 9router v0.4.80 @ b282f05. - Reachable through /v1/chat/completions with a vision-capable model and an imageurl content part. A vision-capable model name is required so the image survives modality stripping and the server-side prefetch is armed. - The provider used in this reproduction is the bundled mock provider — no real API key and no real provider call. - internal-admin (the SSRF target) is not exposed to the host network; it is reachable only from inside the Docker network. - rebind-dns behaviour for rebind.9r.test: - first A response → 1.1.1.1 (public) to pass the…
Recommended action: Upgrade to 0.5.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
9router treats local loopback requests as trusted and allows access to /v1/ without an API key. In a documented/common reverse-proxy deployment where nginx forwards public traffic to the backend via 127.0.0.1, external non-Origin requests are misclassified as local. This allows unauthenticated access to /v1 APIs such as /v1/models, and may allow abuse of configured upstream provider credentials depending on the enabled providers. Details - Affected version / commit: 9router v0.4.80 @ b282f05. - Deployment precondition: a same-host reverse proxy (e.g. nginx) forwarding public traffic to the backend on 127.0.0.1 / localhost. This mirrors the documented cloud deployment (proxypass http://localhost:20128 with X-Real-IP / X-Forwarded-For). - Observed behaviour: - The direct backend (direct-backend, port 18081) returns 401 for /v1/models without an API key. - A direct request that spoofs X-9r-Real-IP: 127.0.0.1 still returns 401: the custom server deletes the client-supplied header…
Recommended action: Upgrade to 0.5.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
9router enforces a progressive login lockout (5 failed attempts → temporary 30s+ lock) keyed on the client IP. The client IP used for this limiter is taken from the X-9r-Real-Ip request header, which is intended to be set only by the bundled custom-server.js layer from the unspoofable TCP socket address. In deployment modes where requests reach Next.js directly, a remote attacker controls this header and can assign a unique value to every request. Because each distinct header value maps to a fresh limiter bucket, the lockout never triggers, enabling unlimited password guessing against the dashboard login endpoint. This was reproduced against a live instance: a fixed header value was locked out (429) after 5 attempts, while rotating the header produced unlimited 401 responses with no lockout. Affected Component - src/lib/auth/loginLimiter.js - getClientIp() — derives the rate-limit bucket key from the client-supplied X-9r-Real-Ip header - checkLock() / recordFail() — per-IP…
Recommended action: Upgrade to 0.5.8 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
9router determines whether an incoming request originates from localhost by trusting the X-9r-Real-Ip HTTP request header. This header is intended to be produced and sanitized exclusively by the bundled custom-server.js layer from the TCP socket address. In deployment modes where requests reach Next.js directly (the header is never stripped/regenerated), a remote, unauthenticated attacker can simply send X-9r-Real-Ip: 127.0.0.1 and be treated as a local client. This bypasses the API-key requirement on the public LLM API (/api/v1/), granting unauthenticated access to the instance owner's configured provider resources. Affected Component - src/dashboardGuard.js - isLocalRequest() — trusts the client-supplied X-9r-Real-Ip header to decide loopback origin - canAccessPublicLlmApi() — grants access to /api/v1/ when isLocalRequest() returns true, skipping API-key validation - Verified affected route: GET /api/v1/models - Product version tested: 9router-app 0.5.4 (Next.js 16.2.9)…
Recommended action: Upgrade to 0.5.8 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
9router's request guard decides a request is "local" (and therefore exempt from API-key auth on the /v1 LLM proxy) by reading the client-controlled Host header. Because 9router binds 0.0.0.0 by default (and the CLI misleadingly prints "localhost"), a remote, unauthenticated attacker who can reach the port can send Host: localhost to be treated as local and obtain /v1 proxy access with no API key, no CLI token, and no dashboard login. In the default configuration (requireApiKey is absent from DEFAULTSETTINGS, so the handler-side key check is skipped), this yields: - Open AI relay — the proxy forwards the attacker's requests to AI providers using the victim's stored paid API keys (cost/quota theft, prompt-based data exfiltration through the victim's accounts). - Unauthenticated SSRF — /v1/search with the built-in noAuth searxng provider takes its outbound fetch URL from the request body (provideroptions.baseUrl), so the attacker drives a server-side fetch to any…
Recommended action: Upgrade to 0.5.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
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 |…
Recommended action: Upgrade to 0.5.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
The 9router dashboard login rate limiter derives the client identity from the attacker-controlled X-Forwarded-For HTTP header. When 9router is directly exposed, or deployed behind a reverse proxy that does not overwrite untrusted forwarding headers, a remote attacker can rotate the X-Forwarded-For value on each login attempt and receive a fresh rate-limit bucket every time. This bypasses the dashboard brute-force protection and makes the login lockout mechanism ineffective. Details | Component | File | Note | | ---------------------------- | --------------------------------- | --------------------------------------------------------------------------- | | Dashboard login rate limiter | src/lib/auth/loginLimiter.js | Uses X-Forwarded-For as the client identity without a trusted-proxy check | | Dashboard login route | src/app/api/auth/login/route.js | Calls checkLock() and recordFail() using the spoofable client identity | Vulnerable Code src/lib/auth/loginLimiter.js: The…
Recommended action: Upgrade to 0.4.77 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
9router uses a publicly known hardcoded string "9router-default-secret-change-me" as the fallback of JWT secret for all Dashboard session JWTs when the JWTSECRET environment variable is not set. Because this secret is committed in the public repository and unchanged across all releases, any unauthenticated remote attacker can forge a valid authtoken cookie and gain full access to dashboard and api (If JWTSECRET is not set on server) . This vulnerable affected so many public 9router server Details | Versions | File | Note | |---|---|---| | = 0.2.21, <= 0.4.30 | src/app/api/auth/login/route.js + src/middleware.js | Introduced in commit 23cfb19 | | = 0.4.31, <= 0.4.41 | src/lib/auth/dashboardSession.js | Relocated by OIDC refactor c3d91b0, secret unchanged | Vulnerable Code v0.2.21 – v0.4.30 — src/app/api/auth/login/route.js and src/middleware.js: v0.4.31 – v0.4.41 (current) — src/lib/auth/dashboardSession.js (centralized via OIDC refactor, commit c3d91b0): The fallback string…
Recommended action: Upgrade to 0.4.45 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Unauthenticated RCE via /api/tunnel/tailscale-install Affected: 9router (npm package) — current master (v0.4.39). Summary POST /api/tunnel/tailscale-install accepts a JSON body with a sudoPassword field and pipes it, followed by the body of https://tailscale.com/install.sh, into a child process spawned as sudo -S sh. The route is not present in the dashboard middleware matcher in src/proxy.js, so the request reaches the handler without invoking dashboardGuard.proxy(). In deployments where the Node process runs as root (Docker images derived from node: without a USER directive, npm i -g 9router invoked as root, or systemd units without User=), the spawned sh runs as root and executes the attacker-supplied bytes. Details 1. Middleware matcher (src/proxy.js:3-15) Next.js invokes the middleware only for paths matching this list. Routes that are not listed — including the entire /api/tunnel/ family — do not invoke dashboardGuard.proxy(). No cookie, JWT, CLI token, or Host-header check is…
Recommended action: Upgrade to 0.4.44 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
9router exposes two unauthenticated API endpoints that, when chained together, allow any network-adjacent attacker to execute arbitrary OS commands as the user running the 9router process — with zero prerequisites and no credentials required. The vulnerability exists because the Next.js middleware that enforces authentication (src/proxy.js) only guards 8 explicitly listed routes. The attack surface of /api/cli-tools/ and /api/mcp/ (40+ routes) receives no authentication whatsoever. --- Root Cause 1. Middleware Allowlist Is Too Narrow File: src/proxy.js Next.js middleware only runs on routes matching this list. Routes NOT listed — including /api/cli-tools/ and /api/mcp/ — bypass the dashboardGuard auth check entirely. 2. Unguarded Endpoint Accepts Arbitrary Command Registration File: src/app/api/cli-tools/cowork-settings/route.js, lines 292–319 The command and args fields from the attacker's JSON are stored verbatim into globalThis.9routerCustomPlugins — a process-global Map…
Recommended action: Upgrade to 0.4.37 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
A security vulnerability has been detected in decolua 9router up to 0.3.47. The impacted element is an unknown function of the file /api of the component Administrative API Endpoint. The manipulation leads to authorization bypass. The attack is possible to be carried out remotely. The exploit has been disclosed publicly and may be used. Upgrading to version 0.3.75 is sufficient to resolve this issue. It is suggested to upgrade the affected component.
Recommended action: Upgrade to 0.3.75 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.