| type | skill |
| lifecycle | stable |
| inheritance | inheritable |
| name | shell-injection-prevention |
| description | Use execFileSync with args array instead of execSync with string concatenation to prevent shell injection |
| tier | standard |
| applyTo | **/*shell*,**/*injection*,**/*prevention* |
| currency | 2026-04-30T00:00:00.000Z |
| lastReviewed | 2026-04-30T00:00:00.000Z |
Shell Injection Prevention
Category: Security
Time Saved: 1+ hour debugging, prevents incidents
Battle-tested: Yes — multiple projects
The Problem
Your Node.js script needs to run external commands (git, npm, az cli). You use execSync("git status") and it works. Then someone passes a filename with a semicolon and your server runs arbitrary commands.
Why It Happens
execSync(command) passes the string to a shell (/bin/sh or cmd.exe), which interprets metacharacters like ;, |, $(), and backticks as command separators or substitutions.
The Rule
Use execFileSync(executable, argsArray) instead of execSync(string)
const output = execSync(`git log --oneline ${filename}`);
const output = execFileSync('git', ['log', '--oneline', filename]);
When Each Is Appropriate
| Use Case | Method | Why |
|---|
| Known executable + args | execFileSync | No shell, no injection |
| Need shell features (pipes, globs) | execSync with allowlist | Validate all inputs |
| User-provided command | Never | Don't execute user commands |
Implementation Patterns
Basic Safe Pattern
const { execFileSync } = require('child_process');
function gitStatus() {
(, [, ], {
: repoPath,
: ,
});
}