Skip to content

GHSA-5mj8-gf6m-fhw8 CVE-2026-56681

9Router has an Authentication Bypass in Public LLM API via Spoofable X-9r-Real-Ip Header

High npm
Severity
7.3 / 10
High · CVSS 3.1
Exploit chance (EPSS)
1.11%
Chance of exploitation in the next 30 days. Higher than 66.02% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-807 Reliance on Untrusted Inputs in a Security Decision
Fix
0.5.8
Upgrade 9router to this version or later

Description

Summary

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)

Root Cause

The authorization layer makes a security decision based on a client-controllable HTTP header. isLocalRequest() reads X-9r-Real-Ip and, if its value is a loopback address (127.0.0.1), classifies the request as local. The design assumes this header can only be set by the trusted custom-server.js wrapper (which derives it from the unspoofable socket address and strips any inbound copy). When the application is served without that wrapper, Next.js passes the attacker-supplied header through unchanged, so the trust assumption is violated:

Untrusted Client Input
        ↓
X-9r-Real-Ip: 127.0.0.1
        ↓
isLocalRequest()  → true
        ↓
canAccessPublicLlmApi()  → allowed (API key not required)
        ↓
200 OK

Attack Scenario

  1. The instance is deployed in a mode that does not use custom-server.js, and the LLM API is reachable by the attacker (the default bind is 0.0.0.0).
  2. The attacker sends a normal request to /api/v1/models and receives 401 Unauthorized (API key required for remote access).
  3. The attacker re-sends the identical request with the single added header X-9r-Real-Ip: 127.0.0.1.
  4. The request is classified as local, the API-key check is skipped, and the attacker receives 200 OK with the owner's model catalog and ongoing access to the LLM API.

Proof of Concept

Baseline Request

<img width="1211" height="402" alt="Screenshot 2026-06-19 174727" src="https://github.com/user-attachments/assets/170b635f-1bd6-4dfd-ad85-30a03a9f6f72" />

Exploit Request

<img width="1207" height="816" alt="Screenshot 2026-06-19 174844" src="https://github.com/user-attachments/assets/b7b4efde-c071-4aa2-ab13-9bde7c88a7b8" />

The only difference between the two requests is the addition of X-9r-Real-Ip: 127.0.0.1.

Impact

An unauthenticated remote attacker who can reach the service can bypass API-key enforcement on the public LLM API and act as a trusted local client. Consequences include:

  • Unauthorized use of the owner's configured LLM provider connections
  • Consumption of paid API credits / financial loss to the instance owner
  • Abuse of upstream provider accounts via the proxy
  • Enumeration of configured providers and available models

Remediation

  • Do not trust X-9r-Real-Ip (or any X-9r-* header) when received directly from clients.
  • Derive the client address for authorization from a trusted transport-level source, e.g. req.socket.remoteAddress, rather than a request header.
  • If custom-server.js is required for the security model, fail closed when its trusted marker is absent, and explicitly strip/reject any inbound client-supplied X-9r-* headers at the edge.
  • Document supported, secure startup modes so the application is not run in a configuration where the header is attacker-controllable.

Affected versions

npm

PackageVulnerableFixed in
9router
< 0.5.8
0.5.8

How to fix

Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.

9router npm → 0.5.8

npm
npm install 9router@0.5.8
yarn
yarn add 9router@0.5.8
pnpm
pnpm add 9router@0.5.8

Severity breakdown

CVSS 3.1 7.3

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
Low
Integrity
Low
Availability
Low

Weakness

CWE-807: Reliance on Untrusted Inputs in a Security Decision

The product uses a protection mechanism that relies on the existence or values of an input, but the input can be modified by an untrusted actor in a way that bypasses the protection mechanism.

How to prevent it
  • Architecture and Design: Store state information and sensitive data on the server side only. Ensure that the system definitively and unambiguously keeps track of its own state and user state and has rules defined for legitimate state transitions. Do not allow any application user to affect state directly in any way other than through legitimate actions leading to state transitions. If information must be stored on the client, do not do so without encryption and integrity checking, or otherwise having a mechanism on the server side to catch tampering. Use a message authentication code (MAC) algorithm, such as Hash Message Authentication Code (HMAC) [REF-529]. Apply this against the state or sensitive data that has to be exposed, which can guarantee the integrity of the data - i.e., that the data has not been modified. Ensure that a strong hash function is used (CWE-328).
  • Architecture and Design: Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid. With a stateless protocol such as HTTP, use a framework that maintains the state for you. Examples include ASP.NET View State [REF-756] and the OWASP ESAPI Session Management feature [REF-45]. Be careful of language features that provide state support, since these might be provided as a convenience to the programmer and may not be considering security.
  • Architecture and Design: For any security checks that are performed on the client side, ensure that these checks are duplicated on the server side, in order to avoid CWE-602. Attackers can bypass the client-side checks by modifying values after the checks have been performed, or by changing the client to remove the client-side checks entirely. Then, these modified values would be submitted to the server.
  • Operation, Implementation: When using PHP, configure the application so that it does not use register_globals. During implementation, develop the application so that it does not rely on this feature, but be wary of implementing a register_globals emulation that is subject to weaknesses such as CWE-95, CWE-621, and similar issues.
  • Architecture and Design, Implementation: Understand all the potential areas where untrusted inputs can enter your software: parameters or arguments, cookies, anything read from the network, environment variables, reverse DNS lookups, query results, request headers, URL components, e-mail, files, filenames, databases, and any external systems that provide data to the application. Remember that such inputs may be obtained indirectly through API calls. Identify all inputs that are used for security decisions and determine if you can modify the design so that you do not have to rely on submitted inputs at all. For example, you may be able to keep critical information about the user's session on the server side instead of recording it within external data.

References

Timeline

  1. Published
  2. Last updated by the source
  3. Latest EPSS score
AdvisorySeverityWhy it's related
GHSA-32gc-64m7-hj7v
9Router has a Login Brute-Force Lockout Bypass via Spoofable X-9r-Real-Ip Header
Medium Also affects 9router
GHSA-8g4w-4ffg-8vgx
9Router: Authenticated Server-Side Request Forgery (SSRF) via OIDC Provider Test Endpoint
High Also affects 9router
GHSA-vmjq-hvgq-2wv4
9router: Mass assignment in PATCH /api/settings allows authenticated authorization downgrade
High Also affects 9router
GHSA-6mwv-4mrm-5p3m
9router: Kiro region injection allows authenticated SSRF with Authorization header forwarding
Medium Also affects 9router
GHSA-x5c9-v98j-722r
9router /v1 APIs has unauthenticated access via reverse proxy locality collapse
High Also affects 9router
GHSA-86m2-fcxq-5q7c
9router: Unauthenticated `/v1` proxy access via `Host`-header spoofing → open AI relay + SSRF
High Also affects 9router
GHSA-8gmq-j984-vp4r
9router: Unauthenticated LLM proxy access via /codex rewrite authorization bypass
High Also affects 9router
GHSA-cmhj-wh2f-9cgx
9router: Image prefetch DNS rebinding allows SSRF to internal services
High Also affects 9router
Is this in your code?

MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.

Check your repos with MergeHarbor