Command Injection Explained

Share

TL;DR

Command injection occurs when user input is passed to shell commands without sanitization. Attackers can append commands using ; | && or backticks to run anything on your server. Never use exec() or system() with user input. Use specific APIs or spawn with argument arrays instead.

How Command Injection Works

Vulnerable: passing user input to exec()
// User wants to ping a host
app.get('/ping', (req, res) => {
  const host = req.query.host;
  exec(`ping -c 1 ${host}`, (error, stdout) => {
    res.send(stdout);
  });
});

// Attacker sends: host=example.com; cat /etc/passwd
// Executed: ping -c 1 example.com; cat /etc/passwd

Full server access: Command injection often leads to complete server compromise. Attackers can read files, install backdoors, pivot to other systems, or mine cryptocurrency on your server.

Injection Characters

  • ; - Command separator
  • | - Pipe to another command
  • && / || - Conditional execution
  • cmd or $(cmd) - Command substitution
  • \n - Newline (new command)

How to Prevent Command Injection

Safe: using spawn with argument array
import { spawn } from 'child_process';

app.get('/ping', (req, res) => {
  const host = req.query.host;

  // Validate input
  if (!/^[a-zA-Z0-9.-]+$/.test(host)) {
    return res.status(400).send('Invalid host');
  }

  // Use spawn with arguments array (no shell!)
  const ping = spawn('ping', ['-c', '1', host]);

  ping.stdout.on('data', (data) => res.write(data));
  ping.on('close', () => res.end());
});

Prevention Rules

  • Avoid shell commands entirely when possible
  • Use spawn() with argument arrays, not exec()
  • Validate and whitelist input strictly
  • Use library APIs instead of command-line tools

Is escaping shell characters enough?

Escaping is error-prone and easy to bypass. Use spawn() with argument arrays which bypasses the shell entirely. If you must use exec(), use a well-tested escaping library.

What about Windows commands?

Windows has different syntax but similar risks. Characters like & | ^ work differently. The same solution applies: avoid shell commands and use argument arrays.

Scan for Injection Vulnerabilities

Our scanner tests for command injection patterns in your code.

Start Free Scan
Vulnerability Guides

Command Injection Explained