Sep 22, 2026·6 min read·16 visits
An authentication bypass in 9Router allows remote attackers to spoof their IP address via the X-9r-Real-Ip header and access sensitive APIs without validation.
CVE-2026-56681 is a high-severity authentication bypass vulnerability in 9Router, an AI router and token-saving proxy. The vulnerability arises from an improper trust boundary where the application relies on the client-controlled HTTP header X-9r-Real-Ip to determine whether an incoming request originates from a local (loopback) environment. In deployments where requests can reach the Next.js backend directly—bypassing the sanitizing custom-server.js wrapper—a remote, unauthenticated attacker can spoof their origin by supplying an X-9r-Real-Ip: 127.0.0.1 header.
The system architecture of 9Router employs a dual-layer setup consisting of a Next.js web application and a custom wrapper server defined in custom-server.js. This wrapper handles incoming client connections, resolves IP addresses from TCP sockets securely, sanitizes spoofable HTTP headers, and proxies requests to the Next.js backend.
Under normal execution, the system relies on this boundary to distinguish administrative loopback traffic from public clients. The core application exposes public LLM API routes under /api/v1/* which are intended to be guarded by robust API key validation mechanisms.
However, the application exposes a dangerous trust boundary by utilizing the custom header X-9r-Real-Ip to bypass security guards. If the Next.js server is directly exposed without the wrapper layer, this header falls entirely under client control, allowing unauthenticated remote access to internal API configurations.
The root cause is classified as CWE-807: Reliance on Untrusted Inputs in a Security Decision. The authentication logic inside the Next.js server utilizes a helper function named isLocalRequest() in src/dashboardGuard.js to authorize administrative operations.
This helper identifies loopback traffic by parsing the X-9r-Real-Ip header and matching it to local loopback addresses like 127.0.0.1 or ::1. It operates under the false assumption that only the trusted custom-server.js wrapper can write or forward this specific header.
If the application is deployed directly via standard platform mechanisms (such as next start on cloud providers or in bare Docker containers), the custom-server.js wrapper is completely bypassed. Consequently, an external attacker can append X-9r-Real-Ip: 127.0.0.1 to their HTTP requests. The backend evaluates this header, falsely asserts that the connection is local, and skips API key validation for all endpoints under /api/v1/*.
The vulnerability lies in how IP evaluation was handled prior to the patch. The custom-server.js file failed to properly validate if the physical socket connection originated from a loopback proxy before processing forwarding headers.
// Vulnerable logic flow in custom-server.js
const wrapped = (req, res) => {
const ip = req.socket && req.socket.remoteAddress ? req.socket.remoteAddress : "";
// Forwarding headers present = request arrived via a reverse proxy; loopback
// socket is the proxy hop, not the end-user, so it must not be trusted as local.
const viaProxy = !!(req.headers["x-forwarded-for"] || req.headers["x-real-ip"]);
// Vulnerable trust of incoming headers occurs hereThe patch introduced strict peer address verification and automated stripping of internal headers. The following diff outlines the secured logic in custom-server.js introduced in version 0.5.6:
@@ -10,10 +10,15 @@ http.createServer = (...args) => {
const rest = args.filter((a) => typeof a !== "function");
if (!handler) return origCreate(...args);
const wrapped = (req, res) => {
- const ip = req.socket && req.socket.remoteAddress ? req.socket.remoteAddress : "";
- // Forwarding headers present = request arrived via a reverse proxy; loopback
- // socket is the proxy hop, not the end-user, so it must not be trusted as local.
- const viaProxy = !!(req.headers["x-forwarded-for"] || req.headers["x-real-ip"]);
+ const socketIp = req.socket && req.socket.remoteAddress ? req.socket.remoteAddress : "";
+ const xff = req.headers["x-forwarded-for"];
+ const xRealIp = req.headers["x-real-ip"];
+ const viaProxy = !!(xff || xRealIp);
+ const isLoopbackProxy = socketIp === "127.0.0.1" || socketIp === "::1" || socketIp === "::ffff:127.0.0.1";
+ // Trust forwarding headers only when the TCP peer is a local reverse proxy.
+ // Direct/public sockets remain keyed by the unspoofable peer address.
+ const proxyIp = xRealIp || (xff ? String(xff).split(",")[0].trim() : "");
+ const ip = isLoopbackProxy && proxyIp ? proxyIp : socketIp;
+ delete req.headers["x-9r-real-ip"];
+ delete req.headers["x-forwarded-for"];
+ delete req.headers["x-9r-via-proxy"];The patched version validates whether socketIp is a true loopback address (127.0.0.1, ::1, or the IPv4-mapped IPv6 equivalent ::ffff:127.0.0.1). If the physical socket is not local, incoming forwarding headers are ignored and stripped, neutralizing spoofing attempts.
To exploit this vulnerability, an attacker must identify a target running 9Router where the Next.js application port (typically 3000) is exposed directly to the network. Alternatively, the target may be behind a reverse proxy that fails to strip custom HTTP headers from client requests.
An attacker craft an HTTP request to the /api/v1/models endpoint while injecting the X-9r-Real-Ip header. This allows the attacker to query the state of the router without providing any Authorization headers.
GET /api/v1/models HTTP/1.1
Host: target-9router-instance:3000
X-9r-Real-Ip: 127.0.0.1
User-Agent: Mozilla/5.0
Accept: application/jsonUpon receiving this request, the backend's local request helper processes the injected header. It returns a 200 OK response containing the configured LLM providers and models, allowing the attacker to make unauthorized inferences using the host's paid API keys.
The impact of this vulnerability is significant for organizations relying on 9Router to manage LLM access. Exploitation allows unauthenticated remote actors to execute cost-incurring inference requests against configured models.
Furthermore, the bypass facilitates information disclosure of internal system configurations and API structures. Attackers can enumerate active service integrations, revealing third-party provider accounts associated with the host.
Because the vulnerability does not provide direct filesystem access or system command execution, the impact on confidentiality, integrity, and availability is rated as Low from a system standpoint, yielding a CVSS score of 7.3.
The fix introduced in version 0.5.6 successfully secures deployments that run through custom-server.js by dropping client-supplied headers. However, structural risks remain if system administrators execute the Next.js server directly via next start or similar commands.
Because the core security guard inside dashboardGuard.js was not modified to independently validate socket origins, deployments bypassing custom-server.js remain vulnerable even on version 0.5.6. The fix is only effective if the wrapper file remains the sole entry point for network traffic.
Additionally, if an upstream reverse proxy is configured to append client IPs rather than overwrite the X-Forwarded-For header, attackers might still manipulate the list parsing logic. Standard hardening must include dropping all X-9r-* headers at the network edge.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
9Router decolua | < 0.5.6 | 0.5.6 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-807 |
| Attack Vector | Network |
| CVSS v3.1 Score | 7.3 |
| Exploit Status | Proof of Concept |
| CISA KEV Status | No |
| Impact | Authentication Bypass / Unauthorized Resource Consumption |
The application makes a security decision based on the content of an HTTP header that can be modified or spoofed by an external attacker.
GeoNode versions prior to 5.0.3 contain an unrestricted file upload vulnerability (CWE-434) within the document and dataset ingestion architecture. Authenticated low-privileged users can bypass upload validation via direct REST API interactions, file extension masquerading, metadata mutation via PATCH requests, or malicious archive submissions. This allows attackers to store and serve dangerous file types, alter on-disk file references, or trigger path traversal and resource exhaustion during archive extraction.
CVE-2026-55649 is a stored Cross-Site Scripting (XSS) vulnerability in GeoNode versions prior to 5.0.3. The flaw exists because document abstract metadata fields are ingested via the metadata management pipeline and stored in the backend database without HTML sanitization or input neutralization. An authenticated attacker with privileges to create or edit document metadata can inject arbitrary HTML and JavaScript payloads into these fields. When another user, such as an administrator, views the affected document page or catalog listing, the unencoded payload is rendered into the Document Object Model (DOM) and executes within the victim's browser session.
CVE-2026-55622 (GHSA-qx75-2p3r-pwm5) is an improper access control vulnerability (CWE-284) in Canonical LXD and LXC Incus (tracked as GHSA-c9f5-j9c3-mhrg). In multi-tenant deployments utilizing project-based isolation, the REST API handler for instance creation via POST /1.0/instances verifies that the authenticated user has authorization in the destination project specified by the query parameter, but fails to verify whether the user holds read or view permissions for the source instance when executing a copy operation across projects. Consequently, an authenticated client restricted to a single project can clone instances or snapshots from unauthorized projects into their own project, resulting in complete disclosure of the target instance filesystem and embedded credentials.
An authorization bypass vulnerability in Canonical LXD (tracked as GHSA-7mr3-28h5-m5vx and CVE-2026-55621, and as GHSA-64f3-v33m-w89f in Linux Containers Incus) allows an authenticated user with restricted project access to copy custom storage volumes and volume snapshots from unauthorized projects. The flaw resides in the storagePoolVolumesPost REST API handler, which verifies permissions on the destination project but fails to check whether the caller holds view entitlements on the source project or volume specified in the request body.
A missing authorization and configuration validation vulnerability in Canonical LXD and LXC Incus allows authenticated users within restricted projects to bypass project security boundaries. By smuggling prohibited low-level configuration directives (such as raw.lxc or raw.qemu) inside instance snapshots or backup archives, an attacker can restore these configurations within a restricted project and execute arbitrary commands with root privileges on the underlying host operating system.
A symbolic link traversal vulnerability (CWE-59) in Canonical LXD and Linux Containers Incus allows an authenticated user with image import permissions to read and write arbitrary files on the host filesystem. During image archive unpacking, the daemon fails to reject top-level symbolic links for the instance `templates` directory. Subsequent requests to the instance template API endpoints follow this symbolic link outside the instance storage directory with root privileges, enabling complete host compromise.