Command injection

Command injection

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 -c that reinterpret input as code. Keep the executable location and PATH trustworthy.

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: userInput is passed to sh -c and executed as a shell command.
  • After: Input is limited to ls or pwd, which are launched without a shell. A trusted PATH must resolve those names to the intended executables.

References