
Remotecodeausführung in DbGate durch functionName-Injection im loadReader-Endpunkt — CVSS 8.8
functionName-InjectionSchweregrad: Hoch (CVSS 8.8)
CWE: CWE-94 — Unsachgemäße Kontrolle der Codegenerierung („Code Injection")
Betroffen: dbgate-api ≤ 7.1.8 (behoben in 7.1.9)
Advisory: GHSA-hv83-ggc4-v385
NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-48017
Credit: Romain Deperne
Der Endpunkt POST /runners/load-reader nimmt einen Parameter functionName entgegen und interpoliert ihn
direkt in einen JavaScript-Template-String, der anschließend in einem geforkten Prozess ausgeführt wird — ohne
Bereinigung oder Validierung. Jeder authentifizierte Benutzer (keine besondere Berechtigung erforderlich) kann aus
dem beabsichtigten Aufruf ausbrechen und beliebiges JavaScript ausführen, was Remote Code Execution auf dem Server
ermöglicht.
Der geforkte Runner setzt require = null als Sandbox, aber process.binding("spawn_sync") bleibt erreichbar:
process.binding("spawn_sync") ist weiterhin erreichbar und startet einen echten Betriebssystemprozess.
Ich habe das Runner-Subsystem von DbGate auf die Lücke zwischen geschützten und ungeschützten Code-Exec-Pfaden
geprüft. Der start()-Runner in runners.js:292 ist ordnungsgemäß abgesichert — er ruft
testStandardPermission('run-shell-script') auf und prüft platformInfo.allowShellScripting.
loadReader() tut konzeptionell dasselbe (es baut und führt ein JS-Loader-Skript aus), hat aber
keine dieser Prüfungen. Ich habe den Datenfluss nachverfolgt:
runners.js:353 loadReader({ functionName, props })
runners.js:366 loaderScriptTemplate(prefix, functionName, ...)
runners.js:64 `... ${compileShellApiFunctionName(functionName)}(${JSON.stringify(props)});`
packageTools.ts:33 return `dbgateApi.${functionName}` // ← no sanitization
functionName wird vom Angreifer kontrolliert und landet in einem ausgeführten Template-String. Das Präfix dbgateApi.
ist das Einzige, was davor steht, und es ist umgehbar: Schließt man den Ausdruck mit toString();,
injiziert die Payload und kommentiert das nachfolgende (${props}) mit // aus, ergibt sich gültiges JS.
Datei: packages/api/src/controllers/runners.js (loadReader → loaderScriptTemplate)
Datei: packages/tools/src/packageTools.ts:33 (compileShellApiFunctionName)
// packageTools.ts:33 — functionName flows in unsanitized
return `dbgateApi.${functionName}`;
// runners.js:64 — interpolated into the executed loader template
`const reader = await ${compileShellApiFunctionName(functionName)}(${JSON.stringify(props)});`
Generiertes (injiziertes) Skript:
const reader = await dbgateApi.toString();
process.binding("spawn_sync").spawn({ file:"/bin/sh", args:["/bin/sh","-c","id"], ... });
dbgateApi.toString//({});
compileShellApiFunctionName() wurde geschrieben, um einen kurzen Namen in einen vollqualifizierten API-Pfad (dbgateApi.<name>) umzuwandeln, wobei implizit darauf vertraut wurde, dass functionName ein Bezeichner ist. Der Wert stammt jedoch direkt aus dem HTTP-Anfragekörper. Da er in Quellcode eingefügt wird, der später eval/geforkt wird, ist die Vertrauensannahme eine RCE. Die Sandbox mit require = null hilft nicht — Nodes internes process.binding("spawn_sync") umgeht sie.
Fix (7.1.9): functionName gegen eine strikte Bezeichner-Allowlist validieren, bevor es in das Loader-Skript kompiliert wird.
poc/rce_loadreader_functionname_injection.py — steuert den echten Endpunkt End-to-End an.
# with an existing JWT
python3 poc/rce_loadreader_functionname_injection.py http://localhost:3000 <JWT> 'id > /tmp/pwned'
# or log in first
python3 poc/rce_loadreader_functionname_injection.py http://localhost:3000 --login admin password 'id'
Das Skript erstellt die functionName-Payload, sendet sie an POST /runners/load-reader, und der
injizierte spawn_sync-Aufruf führt den Befehl im geforkten Runner-Prozess aus.
Authentifizierte RCE auf dem DbGate-API-Host. DbGate ist eine Datenbankverwaltungs-GUI, die häufig mit breiter Netzwerkreichweite zu internen Datenbanken bereitgestellt wird — Codeausführung darauf ist ein starker Pivot in die Datenschicht.
Verantwortungsvoll offengelegt. PoC nach Auslieferung des Fixes veröffentlicht, für Verteidiger und Detection Engineering.