Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
📦
📦 npm
Not in CISA KEV
HIGH severity

9Router has an Authentication Bypass in Public LLM API via Spoofable X-9r-Real-Ip HeaderGHSA-5mj8-gf6m-fhw8

HIGHFix: decolua/9router@efd20be

GHSA-5mj8-gf6m-fhw8 is a high-severity (CVSS 7.3) CWE-807 vulnerability in 9router. A fix is available for 9router — see the affected versions and patch details below.

Also known asCVE-2026-56681
Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Oct 23, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
  • CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.

Exploitation and automatability from CISA’s SSVC triage for GHSA-5mj8-gf6m-fhw8.

EPSS Exploitation Probability

via FIRST.org ↗
1.0%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs61th percentile — riskier than 61% of all scored CVEsHighest risk
0.47%0.80%1.13%1.47%1.0%1.0%Oct 26Oct 26

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

How urgent is this, really

GHSA-5mj8-gf6m-fhw8 by exploitation likelihood (EPSS) against impact (CVSS). Outside the shaded patch-first corner.

Where this sits among everything scored

Of 394,803 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Counts from FIRST.org, log-scaled.

Real-World Exposure

1 pkg affected

How broadly this vulnerability is actually deployed: weekly install volume shows current usage, and reverse-dependency count shows how many other packages break if it stays unpatched.

2other npm packages depend on this — each one inherits the vulnerability until it's patched upstream
9routernpm
38Kdownloads / week

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 Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
📦npm9routerall versions0.5.8npm install 9router@0.5.8

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for 9router, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update 9router to 0.5.8 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-5mj8-gf6m-fhw8 is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

How to detect GHSA-5mj8-gf6m-fhw8

A community-maintained Nuclei template exists for this CVE. You can scan for it directly:

nuclei -id ghsa-5mj8-gf6m-fhw8 -u https://target
Template
9router <=0.5.4 - Authentication Bypass
Severity
high
Impact
Remote attackers can bypass API-key validation to use LLM providers, consume paid credits, and enumerate models without authorization.
Remediation
Update to version 0.5.6 or later.

Template by ProjectDiscovery nuclei-templates (0x_Akoko), MIT licensed. View the full template. Scan only systems you are authorised to test.

Frequently Asked Questions

## 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 o
O3 Security · Impact-Aware SCA

Is GHSA-5mj8-gf6m-fhw8 in your dependencies?

Find it across npm, including transitive dependencies.

9Router has an Authentication Bypass in Public LLM API…