Summary
A command injection vulnerability in the _extractLLM() function allows attackers to execute arbitrary shell commands on the server. The function constructs a curl command using string concatenation and passes it to execSync() without proper sanitization, enabling remote code execution when the corpus parameter contains shell metacharacters.
Details
The vulnerability exists in src/gep/signals.js at lines 260-274:
// src/gep/signals.js:260-274
function _extractLLM(corpus, nodeSecret, hubUrl) {
// ...
var url = getHubUrl(hubUrl) + '/gep/extract';
var postData = JSON.stringify({ corpus_summary: summary });
// VULNERABLE: String concatenation into shell command
var curlCmd = 'curl -s -m 10 -X POST'
+ ' -H "Content-Type: application/json"'
+ ' -H "Authorization: Bearer ' + nodeSecret + '"'
+ ' -d ' + JSON.stringify(postData).replace(/'/g, "'\\''")
+ ' ' + JSON.stringify(url);
// VULNERABLE: Executes shell command
stdout = execSync(curlCmd, { timeout: 12000, encoding: 'utf8' });
// ...
}
The corpus parameter is derived from user input (via userSnippet in extractSignals() function) and flows through to _extractLLM() where it becomes part of the shell command. While JSON.stringify() escapes some characters, it does not prevent shell command substitution via $(...) syntax when the resulting string is passed to execSync().
The extractSignals() function is called from the main evolution loop in src/gep/evolver.js, which processes user snippets and session transcripts.
PoC
Prerequisites:
- Node.js installed
- Access to the evolver application
Steps to reproduce:
- Create a test file that simulates the vulnerable code path: