no-child-process-exec
Disallow child_process.exec() and child_process.execSync() shell-backed execution APIs.
Targeted pattern scopeโ
This rule targets exec() and execSync() when they are imported from
child_process or node:child_process, destructured from require(...), or
called through a namespace binding created from those modules.
What this rule reportsโ
This rule reports direct use of child_process.exec() and
child_process.execSync() because both APIs execute a command string through a
shell.
Why this rule existsโ
Shell-backed command execution is harder to review safely than argv-separated process launches. When user-controlled data is concatenated into a command string, it can become command injection.
For SDL-oriented code review, spawn() and execFile() are generally easier
to reason about because they keep the executable path and the arguments
separate.
โ Incorrectโ
import { exec } from "node:child_process";
exec(`git show ${userSuppliedRef}`);
const { execSync } = require("child_process");
execSync("tar -xf " + archivePath);
import * as childProcess from "node:child_process";
childProcess.exec("convert " + inputPath);
โ Correctโ
import { execFile } from "node:child_process";
execFile("git", ["show", userSuppliedRef]);
const { spawn } = require("child_process");
spawn("tar", ["-xf", archivePath], { shell: false });
Behavior and migration notesโ
This rule intentionally focuses on direct child_process bindings and does not
attempt to reason about custom wrapper utilities that may call exec()
internally.
ESLint flat config exampleโ
import sdl from "eslint-plugin-sdl-2";
export default [
{
plugins: { sdl },
rules: {
"sdl/no-child-process-exec": "error",
},
},
];
When not to use itโ
If your project intentionally permits shell-backed command execution and you already review all command construction paths carefully, this rule may be too strict.
Package documentationโ
Further readingโ
Rule catalog ID: R062