CVE-2026-49353

HIGHPre-NVD 7.57.5
EchelonGraph scoreHIGH confidence

Score 7.5 from GitHub Security Advisory (severity: HIGH) published 2026-07-02. the CNA's CVSS baseline 7.5; sources differ by 0.0.

Triggered by: GitHub Security Advisory CVSS
Sources: cna:github_m, ghsa
7.5
EchelonGraph verdictPlan a fixSerious severity, but no confirmed exploitation yet.
  • High severity, but no confirmed exploitation yet
CISA-KEV: Not listedEPSS: CVSS: 7.5Exploit: NoneExposed: 0

No vendor fix yet — apply a workaround or compensating control (WAF / firewall / segmentation) and watch for a patch.

9router has an Incomplete Fix: Local-Only Access Gate Bypass in 9router via Host Header SpoofING

Summary

The fix for CVE-2026-46339 (unauthenticated RCE via unprotected MCP plugin routes) introduced a local-only access gate in src/dashboardGuard.js that restricts spawn-capable routes (/api/mcp/*, /api/tunnel/*, /api/cli-tools/*) to loopback requests. The gate determines "local" by inspecting the Host and Origin HTTP headers rather than the TCP source address. When 9router is deployed behind a reverse proxy, tunnel (Cloudflare Tunnel, Tailscale — both natively supported), or is subject to DNS rebinding, these headers are attacker-controlled, allowing the local-only gate to be bypassed.

A second factor (CLI token or JWT cookie) is required by canAccessLocalOnlyRoute(), but the CLI token is a deterministic HMAC of the machine ID (getConsistentMachineId), which is stable and predictable on cloud VMs. If the attacker can obtain or guess the machine ID (e.g., via another information disclosure, or on shared-tenant infrastructure), the full chain to MCP child process stdin injection is reachable.

This is a variant / incomplete fix of CVE-2026-46339 — the same attack surface (remote → MCP child process stdin) remains reachable under specific but realistic deployment configurations.

Root Cause

isLocalRequest() at src/dashboardGuard.js:93-101:

function isLocalRequest(request) {
  if (!isLoopbackHostname(request.headers.get("host"))) return false;
  const origin = request.headers.get("origin");
  if (origin) {
    try {
      if (!isLoopbackHostname(new URL(origin).hostname)) return false;
    } catch { return false; }
  }
  return true;
}

This function trusts Host and Origin headers as proof of local origin. Both are attacker-controlled in any proxied deployment. The LOOPBACK_HOSTS set (localhost, 127.0.0.1, ::1) is checked against these headers, not against the actual connection source IP.

Attack Scenario

Scenario 1: Cloudflare Tunnel / Tailscale Funnel

9router natively supports Cloudflare Tunnel and Tailscale (see LOCAL_ONLY_PATHS entries for /api/tunnel/*). When exposed via tunnel:

  • Attacker sends request to https:///api/mcp//sse
  • Sets Host: localhost:3000 and Origin: http://localhost:3000
  • isLocalRequest() returns true
  • canAccessLocalOnlyRoute() then requires CLI token or (local + JWT)
  • CLI token is getConsistentMachineId("9r-cli-auth") — a deterministic HMAC of the machine's hardware/OS identifiers

Scenario 2: DNS Rebinding

  • Attacker controls evil.com DNS, initially resolving to attacker IP
  • Victim's browser navigates to evil.com (or via iframe/redirect)
  • DNS rebinding switches evil.com127.0.0.1
  • Subsequent fetch to evil.com:3000/api/mcp//message reaches 9router
  • Host header is evil.com:3000 — this is blocked by the current check (not in LOOPBACK_HOSTS)
  • However, if the attacker uses localhost:3000 as the request host via CORS or service worker tricks, and the browser sends Host: localhost:3000, the gate opens

Exploitation (when CLI token is obtained)

Once past the gate, the attacker can:

  • GET /api/mcp//sse — establish SSE session, get sessionId
  • POST /api/mcp//message — send arbitrary JSON-RPC to the child process stdin
  • The child process is one of: npx, node, python, python3, uvx, bunx, bun
  • Depending on the MCP plugin implementation, this can achieve arbitrary code execution on the host

Steps to Reproduce

  • Deploy 9router behind a reverse proxy or tunnel
  • From a remote host, send:

GET /api/mcp/browser/sse HTTP/1.1
Host: localhost:3000
Origin: http://localhost:3000
x-9r-cli-token:
  • Observe: SSE connection established, endpoint event received with message URL
  • POST arbitrary JSON-RPC to the message endpoint

Impact

An attacker who can reach a proxied/tunneled 9router instance and obtain the deterministic CLI token can bypass the local-only restriction and interact with MCP child processes (node, python, npx, etc.) via stdin. This achieves the same impact as CVE-2026-46339: remote code execution on the host.

The severity is reduced from CVE-2026-46339's CVSS 10.0 because:

  • Requires proxied/tunneled deployment (not default localhost-only)
  • Requires obtaining the CLI token (deterministic but not trivially guessable without another primitive)

Remediation

  • Check actual source IP, not headers. Use request.ip, request.socket.remoteAddress, or a trusted X-Forwarded-For header with known proxy configuration instead of Host/Origin for the local-only gate.
  • Make CLI token non-deterministic. Generate a random token on first run and persist it, rather than deriving from machine ID. Machine IDs are often predictable or discoverable on cloud infrastructure.
  • Bind MCP routes to loopback at the network layer. If MCP is local-only by design, the server should bind those routes to 127.0.0.1 only, not rely on middleware header checks.

Credit: @snailsploit

CVSS v3
7.5
EG Score
7.5(high)
EPSS
KEV
Not listed

Published

July 2, 2026

Last Modified

July 2, 2026

Vendor Advisories for CVE-2026-49353(1)

These vendors published their own advisory mentioning this CVE — often with vendor-specific remediation steps + affected product lists not in NVD.

Patch Availability(1)

Vendor / EcosystemFixed in / PatchReleasedSource
npm9routerghsa

Patches are aggregated from vendor advisories (Red Hat, Microsoft, Cisco, GitHub) and package ecosystems (OSV, GHSA). Multiple rows for the same upstream release have been deduplicated.

Weakness Classification(1)

MITRE Common Weakness Enumeration — the root-cause categories this CVE belongs to.

Data Freshness Timeline

(refreshed 18× in last 7d / 18× in last 30d)

Each row is a source pipeline that fetched or updated this CVE on that date, with what changed. For example, "NVD update" means NVD published or revised its analysis for this CVE; "MITRE cvelistV5" means we ingested or refreshed it from the CNA feed. Most recent first.

  1. 2026-07-07 01:17 UTCEG score recompute
  2. 2026-07-07 01:17 UTCGHSA enrichment
  3. 2026-07-06 12:54 UTCEG score recompute
  4. 2026-07-06 12:54 UTCGHSA enrichment
  5. 2026-07-06 00:29 UTCEG score recompute
  6. 2026-07-06 00:29 UTCGHSA enrichment
  7. 2026-07-05 12:06 UTCEG score recompute
  8. 2026-07-05 12:06 UTCGHSA enrichment
  9. 2026-07-04 23:43 UTCEG score recompute
  10. 2026-07-04 23:43 UTCGHSA enrichment
  11. 2026-07-04 11:20 UTCEG score recompute
  12. 2026-07-04 11:20 UTCGHSA enrichment
  13. 2026-07-03 22:57 UTCEG score recompute
  14. 2026-07-03 22:57 UTCGHSA enrichment
  15. 2026-07-03 10:33 UTCEG score recompute
  16. 2026-07-03 10:32 UTCGHSA enrichment
  17. 2026-07-02 22:07 UTCEG score recompute
  18. 2026-07-02 22:07 UTCGHSA enrichment

Frequently asked(4)

What is CVE-2026-49353?
CVE-2026-49353 is a high vulnerability published on July 2, 2026. 9router has an Incomplete Fix: Local-Only Access Gate Bypass in 9router via Host Header SpoofING Summary The fix for CVE-2026-46339 (unauthenticated RCE via unprotected MCP plugin routes) introduced a local-only access gate in src/dashboardGuard.js that restricts spawn-capable routes (/api/mcp/,…
When was CVE-2026-49353 disclosed?
CVE-2026-49353 was first published in the National Vulnerability Database on July 2, 2026. EchelonGraph re-ingests CVE updates from NVD on a 2-hour cycle, so this page reflects the latest published state.
What is the CVSS score of CVE-2026-49353?
CVE-2026-49353 has a CVSS v4.0 base score of 7.5 (CNA self-assessment; NVD's own analysis pending).
How do I remediate CVE-2026-49353?
Patch to the fixed version published by the affected vendor. Where vendor advisories exist for CVE-2026-49353, EchelonGraph cross-links them in the Vendor Advisories panel below — those typically contain the canonical remediation steps, fixed version numbers, and any vendor-specific mitigations.

Dependency Blast Radius

Explore the affected products and dependency analysis for CVE-2026-49353

Explore →

Is Your Infrastructure Affected by CVE-2026-49353?

EchelonGraph automatically scans your cloud infrastructure and maps CVE exposure using blast radius analysis.