CVE-2026-55641 Overview
9Router is an AI router and token saver used to proxy requests to upstream large language model (LLM) providers. Versions prior to 0.5.2 determine whether an incoming /v1 proxy request is local by inspecting the client-controlled Host header. A remote unauthenticated attacker can send Host: localhost to bypass API-key authentication entirely. In the default configuration, this exposes the /v1 proxy to upstream provider calls using stored credentials and permits /v1/search requests with the searxngprovider_options.baseUrl parameter to reach internal or cloud-metadata endpoints. The issue is fixed in version 0.5.2.
Critical Impact
Unauthenticated remote attackers can abuse stored LLM provider credentials and pivot to internal services or cloud instance metadata via server-side request forgery (SSRF).
Affected Products
- 9Router versions prior to 0.5.2
- Deployments exposing the default /v1 LLM proxy endpoint
- Instances configured with the searxng search provider
Discovery Timeline
- 2026-07-10 - CVE-2026-55641 published to NVD
- 2026-07-10 - Last updated in NVD database
Technical Details for CVE-2026-55641
Vulnerability Analysis
The vulnerability is an authentication bypass classified as improper authentication [CWE-290]. 9Router differentiates local traffic from remote traffic by reading the Host HTTP header. When the header value matches localhost, the server treats the request as trusted and skips API-key validation. An attacker controls this header trivially, so any remote client can present itself as local.
Once authentication is skipped, two abuse paths open. First, the /v1 proxy forwards requests to upstream LLM providers using credentials stored by the 9Router operator, letting the attacker consume paid API quota. Second, the /v1/search endpoint accepts a provider_options.baseUrl parameter for the searxng provider, enabling server-side request forgery against internal network hosts and cloud instance metadata services such as 169.254.169.254.
Root Cause
The root cause is trusting the client-supplied Host header as a security boundary. Host header values are attacker-controlled and cannot be used to authenticate the origin of a request. The fix in version 0.5.2 replaces host-header inspection with a proper binding check and introduces an allowlist that blocks SSRF targets including 127.0.0.1, ::1, 169.254.169.254, and metadata.google.internal.
Attack Vector
Exploitation requires only network reachability to the 9Router service on its listening port. The attacker sends an HTTP request to /v1/chat/completions or /v1/search with a spoofed Host: localhost header, no API key, and a crafted body that triggers upstream provider calls or SSRF via provider_options.baseUrl.
// Security patch in cli/cli.js (v0.5.2)
const DEFAULT_PORT = 20128;
const DEFAULT_HOST = "0.0.0.0";
// First non-internal IPv4 — the address remote peers actually reach when bound to 0.0.0.0.
function getLanIp() {
for (const ifaces of Object.values(os.networkInterfaces())) {
for (const i of ifaces || []) {
if (i.family === "IPv4" && !i.internal) return i.address;
}
}
return null;
}
// Local URL stays "localhost"; warn separately when bound to all interfaces (network-exposed).
function getDisplayHost() {
return host === DEFAULT_HOST ? "localhost" : host;
}
Source: GitHub Commit b282f055
The patch also introduces an SSRF blocklist for remote media and search fetches:
// open-sse/config/mediaConfig.js (v0.5.2)
// Hostnames/IPs that must never be fetched (SSRF guard for loopback + cloud metadata).
export const BLOCKED_HOSTS = new Set([
"localhost",
"127.0.0.1",
"0.0.0.0",
"::1",
"169.254.169.254", // AWS/GCP/Azure IMDS
"metadata.google.internal",
]);
Source: GitHub Commit b282f055
Detection Methods for CVE-2026-55641
Indicators of Compromise
- Inbound HTTP requests to /v1/* endpoints containing Host: localhost or Host: 127.0.0.1 from external source IPs.
- Outbound requests from the 9Router host to 169.254.169.254, metadata.google.internal, or RFC1918 addresses following a /v1/search invocation.
- Unexpected billing spikes or usage anomalies on upstream LLM provider accounts linked to the 9Router deployment.
Detection Strategies
- Correlate HTTP access logs on the 9Router listener for Host header values that do not match the actual bound interface or reverse-proxy configuration.
- Alert on any /v1/search request body containing a provider_options.baseUrl value pointing to loopback, link-local, or internal ranges.
- Baseline outbound network flows from the 9Router process and flag deviations toward instance metadata endpoints.
Monitoring Recommendations
- Enable verbose request logging on 9Router and forward logs to a centralized SIEM or data lake for correlation.
- Monitor upstream LLM provider API usage dashboards for unauthorized token consumption.
- Deploy egress filtering that blocks the 9Router service from reaching cloud metadata IPs and internal management networks.
How to Mitigate CVE-2026-55641
Immediate Actions Required
- Upgrade 9Router to version 0.5.2 or later without delay.
- Rotate all upstream LLM provider API keys stored in the 9Router configuration, since prior keys may have been abused.
- Restrict network exposure of the 9Router listener to trusted management networks using firewall rules or a reverse proxy with authentication.
Patch Information
The fix ships in 9Router 0.5.2. The patch replaces the client-controlled Host header check with a binding-based determination of local traffic and introduces a BLOCKED_HOSTS allowlist that rejects fetches to loopback, 0.0.0.0, ::1, 169.254.169.254, and metadata.google.internal. Details are available in the GitHub Security Advisory GHSA-86m2-fcxq-5q7c and the GitHub Release v0.5.2.
Workarounds
- Bind 9Router to 127.0.0.1 instead of 0.0.0.0 so the service is not reachable from remote networks.
- Place 9Router behind a reverse proxy that strips or validates the Host header and enforces authentication before requests reach the application.
- Apply egress firewall rules blocking the 9Router process from initiating connections to 169.254.169.254, metadata.google.internal, and internal RFC1918 ranges.
# Configuration example: bind to loopback only and block metadata egress
# 1. Start 9router bound to localhost (not exposed to LAN)
node cli/cli.js --host 127.0.0.1 --port 20128
# 2. Block outbound access to cloud metadata from the 9router host
sudo iptables -A OUTPUT -d 169.254.169.254 -j DROP
sudo iptables -A OUTPUT -d 127.0.0.0/8 ! -o lo -j DROP
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

