
Ejecución remota de código en DbGate mediante inyección de functionName en el endpoint loadReader — CVSS 8.8
functionNameSeveridad: Alta (CVSS 8.8)
CWE: CWE-94 — Control inadecuado de la generación de código ('Inyección de código')
Afectado: dbgate-api ≤ 7.1.8 (corregido en 7.1.9)
Aviso: GHSA-hv83-ggc4-v385
NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-48017
Crédito: Romain Deperne
El endpoint POST /runners/load-reader toma un parámetro functionName y lo interpola directamente en una cadena de plantilla de JavaScript que luego se ejecuta en un proceso bifurcado — sin saneamiento ni validación. Cualquier usuario autenticado (sin necesidad de permisos especiales) puede escapar de la llamada prevista y ejecutar JavaScript arbitrario, logrando ejecución remota de código en el servidor.
El runner bifurcado establece require = null como sandbox, pero eso se elude trivialmente: process.binding("spawn_sync") sigue siendo accesible y genera un proceso real del sistema operativo.
Estaba auditando el subsistema de runners de DbGate para encontrar la brecha entre las rutas de ejecución de código protegidas y desprotegidas. El runner start() en runners.js:292 está correctamente controlado — llama a testStandardPermission('run-shell-script') y verifica platformInfo.allowShellScripting.
loadReader() hace algo conceptualmente similar (construye y ejecuta un script loader de JS) pero no tiene ninguna de esas comprobaciones. Tracé el flujo de datos:
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 está controlado por el atacante y termina dentro de una cadena de plantilla ejecutada. El prefijo dbgateApi. es lo único que está delante, y se puede escapar: cerrando la expresión con toString();, inyectando el payload y comentando el (${props}) final con // se obtiene JS válido.
Archivo: packages/api/src/controllers/runners.js (loadReader → loaderScriptTemplate)
Archivo: 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)});`
Script generado (inyectado):
const reader = await dbgateApi.toString();
process.binding("spawn_sync").spawn({ file:"/bin/sh", args:["/bin/sh","-c","id"], ... });
dbgateApi.toString//({});
compileShellApiFunctionName() fue escrita para convertir un nombre corto en una ruta de API totalmente cualificada (dbgateApi.<name>), confiando implícitamente en que functionName fuera un identificador. Sin embargo, el valor proviene directamente del cuerpo de la petición HTTP. Debido a que se concatena en código fuente que luego se evalúa/bifurca, la suposición de confianza se convierte en un RCE. El sandbox require = null no ayuda — el process.binding("spawn_sync") interno de Node lo elude.
Corrección (7.1.9): validar functionName contra una lista blanca estricta de identificadores antes de compilarlo en el script loader.
poc/rce_loadreader_functionname_injection.py — ejecuta el endpoint real de extremo a extremo.
# 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'
El script construye el payload functionName, lo envía a POST /runners/load-reader, y la llamada inyectada spawn_sync ejecuta el comando en el proceso runner bifurcado.
RCE autenticado en el host de la API de DbGate. DbGate es una GUI de gestión de bases de datos que se despliega frecuentemente con amplio alcance de red a bases de datos internas — la ejecución de código en él es un fuerte pivote hacia la capa de datos.
Divulgado de manera responsable. PoC publicado después de que la corrección se publicara, para defensores e ingeniería de detección.