CVE-2026-55500 Overview
CVE-2026-55500 affects 9Router, an AI router and token saver application. The /api/settings/database endpoint permits full database export and import operations without adequate authentication. An attacker with only a low-privilege JWT or CLI token can exfiltrate the complete database containing credentials, API keys, OAuth tokens, and application settings. The same endpoint allows a full database overwrite through import, letting an attacker replace stored state with attacker-controlled data. The issue is fixed in version 0.4.80 and falls under Information Exposure [CWE-200].
Critical Impact
An authenticated low-privilege user can export all secrets stored by 9Router or completely overwrite the application database, breaking confidentiality, integrity, and availability at once.
Affected Products
- 9Router versions prior to 0.4.80
- /api/settings/database API endpoint
- Deployments relying on the ALWAYS_PROTECTED middleware for sensitive routes
Discovery Timeline
- 2026-07-10 - CVE-2026-55500 published to NVD
- 2026-07-10 - Last updated in NVD database
- 0.4.80 - Fixed release published on GitHub
Technical Details for CVE-2026-55500
Vulnerability Analysis
The vulnerability lives in the database management route at src/app/api/settings/database/route.js. Both GET (export) and POST (import) handlers relied solely on the ALWAYS_PROTECTED middleware. That middleware validates only the presence of a JWT session or a CLI token. It does not require the dashboard password, does not enforce role separation, and does not require re-authentication for destructive operations. Any principal who can obtain a valid session can therefore call the export handler to retrieve a JSON dump of the local database. The same principal can send an import payload that replaces the entire database, including admin credentials and OAuth tokens.
Root Cause
The root cause is missing step-up authentication on high-impact administrative endpoints. Sensitive operations were guarded by the same coarse session check applied to routine dashboard requests. The application also shipped a default password of 123456, which amplifies the risk when combined with weak session controls.
Attack Vector
The attack vector is network-based. An attacker who obtains any valid dashboard JWT, whether through the default password, credential reuse, or session theft, can issue a single GET /api/settings/database request to exfiltrate every secret managed by 9Router. A follow-up POST to the same endpoint can implant attacker-controlled credentials.
// Security patch in src/app/api/settings/database/route.js
// Source: https://github.com/decolua/9router/commit/0c7c9de00ae3ab81d6580e3cc368483c4c03f6fd
import { NextResponse } from "next/server";
import { exportDb, getSettings, importDb } from "@/lib/localDb";
import { applyOutboundProxyEnv } from "@/lib/network/outboundProxy";
+import { verifyDashboardPassword } from "@/lib/auth/dashboardSession";
-export async function GET() {
+const CLI_TOKEN_HEADER = "x-9r-cli-token";
+const PASSWORD_HEADER = "x-9r-password";
+
+// CLI token requests are already trusted (local machine); skip password re-auth.
+function isCliRequest(request) {
+ return Boolean(request.headers.get(CLI_TOKEN_HEADER));
+}
+
+export async function GET(request) {
try {
+ if (!isCliRequest(request) && !(await verifyDashboardPassword(request.headers.get(PASSWORD_HEADER)))) {
+ return NextResponse.json({ error: "Invalid password" }, { status: 401 });
+ }
const payload = await exportDb();
return NextResponse.json(payload);
} catch (error) {
The patch adds an explicit password re-authentication step via verifyDashboardPassword before export or import can proceed, while preserving local CLI trust through the x-9r-cli-token header.
Detection Methods for CVE-2026-55500
Indicators of Compromise
- Unexpected GET requests to /api/settings/database from web browser sessions or non-CLI clients.
- POST requests to /api/settings/database that are not part of a documented administrator restore workflow.
- Response payloads from /api/settings/database exceeding normal API sizes, indicating a full database dump.
- Sudden changes to stored API keys, OAuth tokens, or admin password hashes without a corresponding admin action.
Detection Strategies
- Alert on any access to /api/settings/database outside of scheduled backup jobs or approved admin IP ranges.
- Correlate export requests with subsequent outbound traffic containing large JSON payloads to non-approved destinations.
- Compare running 9Router versions against 0.4.80 and flag any host still exposing the vulnerable route.
Monitoring Recommendations
- Enable HTTP access logging for the 9Router Next.js application and forward logs to a centralized SIEM.
- Monitor for authentication events that use the default password 123456 and require rotation.
- Track integrity of stored credentials by hashing key configuration fields and alerting on unexpected changes.
How to Mitigate CVE-2026-55500
Immediate Actions Required
- Upgrade 9Router to version 0.4.80 or later without delay.
- Rotate every credential, API key, and OAuth token stored in 9Router, assuming prior exposure.
- Replace the default dashboard password 123456 with a strong, unique value on every deployment.
- Restrict network access to the 9Router dashboard to trusted administrator networks or VPN ranges.
Patch Information
The fix is available in GitHub Release v0.4.80. Technical details are documented in GitHub Security Advisory GHSA-qvfm-67h2-2qfx and the code changes in the GitHub Commit Changes. The patch introduces verifyDashboardPassword re-authentication and adds a Server-Side Request Forgery (SSRF) guard on outbound web fetches.
Workarounds
- If patching is not immediately possible, block /api/settings/database at a reverse proxy or Web Application Firewall (WAF) for all non-administrator sources.
- Terminate all active dashboard sessions and require password rotation before re-issuing tokens.
- Isolate 9Router deployments behind an authenticated reverse proxy that enforces an additional identity check.
# Example nginx rule to block external access to the vulnerable endpoint
location = /api/settings/database {
allow 10.0.0.0/8; # trusted admin subnet
deny all;
proxy_pass http://127.0.0.1:3000;
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

