Description
Command injection occurs when unvalidated user input is executed as an operating-system command. Node.js's child_process.exec and execSync use a shell. spawn and spawnSync do not use a shell by default, but shell: true or an explicit interpreter such as sh -c lets a caller inject shell commands. User-selected executables and arguments also need limits on permitted behavior.
Potential impact
- Unintended commands running with the application process's permissions
- Data exposure or modification, including file access or deletion
- Denial of service or other disruption
Remediation
- Do not execute user input as a command string. Use a fixed executable with validated arguments passed as an array.
- If input selects an operation, restrict it to an allow-list.
- Avoid interpreter calls such as
sh -cthat reinterpret input as code. Keep the executable location andPATHtrustworthy.
Examples
Before
javascript
const {spawnSync} = require('child_process');
function runCommand(userInput) {
// Run the user-supplied command directly
spawnSync('sh', ['-c', userInput]);
}
After
javascript
const {spawnSync} = require('child_process');
function runCommandSafe(userInput) {
// Accept only predefined commands
const allowedCommands = ['ls', 'pwd'];
if (!allowedCommands.includes(userInput)) {
throw new Error('허용되지 않은 명령어입니다.');
}
spawnSync(userInput, []);
}
Explanation:
- Before:
userInputis passed tosh -cand executed as a shell command. - After: Input is limited to
lsorpwd, which are launched without a shell. A trustedPATHmust resolve those names to the intended executables.