highUser input reaching your database or shell

Shell Command Built From Variables

A shell command is put together from variables and handed to a shell.

Why it matters

The shell treats characters like ; and | as instructions, so anything that ends up inside the command string is executed, not just passed as text. Passing arguments as an array with no shell removes the interpretation entirely, which is what you wanted in the first place.

What it looks like

This is the shape of code that triggers the rule. AI tools produce it because it works, and nothing tells them it is unsafe.

exec with a template string
exec(`convert ${req.body.file} out.png`, cb);

The smallest fix

minimal patch
import { execFile } from 'node:child_process';
// Arguments go in an array; no shell parses them
execFile('ffmpeg', ['-i', inputPath, '-o', outputPath], (err, stdout) => { ... });

The better fix

If you have a few more minutes, this is the approach that holds up as the app grows.

safe alternative
// Prefer a library over a shell call where one exists (sharp instead of
// ImageMagick, simple-git instead of git commands). If you truly need a
// shell feature, validate the input against a strict allow-list first.

Let your AI tool fix it

When the scanner finds this in your project, it fills in the file and line for you. This is the prompt it gives you to paste into Claude Code, Cursor or whatever you use.

In [the file] at line [the line number] a shell command is built from variables: [the flagged code]. Replace exec with execFile (or spawn without shell: true) and pass every argument as an array element. If a value comes from user input, validate it against an allow-list or a strict pattern before it reaches the command. Add a test that passes a value containing a semicolon and asserts it is treated as plain text.

How to check the fix worked

1. Call the feature with an input that contains "; echo test" and confirm
   nothing extra runs and the input is used literally.
2. Confirm the normal case still works.

Further reading