What node-cmd is—and is not
It does
- Expose shell, direct-file, buffered, synchronous, Promise, and streaming execution paths.
- Forward caller-selected Node child-process options.
- Return the real process handle where Node provides one.
- Keep direct arguments separate unless a shell is explicitly enabled.
It does not
- Sanitize a shell command or decide whether input is trusted.
- Provide a privilege, sandbox, container, or authorization boundary.
- Hide secrets in arguments, environment variables, or captured output.
- Guarantee a hard deadline or terminate every descendant process.
Strings are programs interpreted by a shell
run(), runPromise(), and runSync() execute a command string through the platform shell. Metacharacters, substitutions, redirection, pipelines, and separators are executable syntax.
Unsafe interpolation
// userValue can alter the command
cmd.run(`tool --name ${userValue}`);Separated argument
// userValue remains one argument
cmd.runFile('tool', [
'--name', userValue
]);options.shell.Direct methods reduce shell-injection exposure
runFile(), runFilePromise(), runFileSync(), and runStream() pass an executable and argument array to Node without a shell by default. Spaces, semicolons, ampersands, and quotes remain characters inside an argument.
This does not make every executable safe. The launched program may interpret file paths, configuration, flags, response files, templates, URLs, or other arguments as its own control language. Validate executable selection and the meaning of every value.
| Boundary | Default parser | Primary risk | Preferred use |
|---|---|---|---|
run* | Platform shell | Shell injection and platform-specific parsing | Intentional pipelines, redirection, and shell built-ins |
runFile* | Target executable | Executable-specific argument interpretation | Buffered calls with exact arguments |
runStream | Target executable | Executable behavior and unbounded stream handling | Interactive, long-running, or high-output processes |
Working directory, environment, and executable resolution
- Resolve
cwddeliberately. Do not let another user select an arbitrary directory. Confirm the target exists and stays inside the intended workspace. - Minimize
env. Child processes may inherit tokens, credentials, proxy settings, search paths, and debug flags. Pass only values the program needs. - Control executable lookup. A modified
PATHcan select a different program with the same name. Use an absolute path when executable identity matters. - Avoid attacker-controlled configuration. Programs often load project-local files, plugins, startup scripts, or environment-based hooks from the selected directory.
Secrets and output are caller-owned
Command lines can be visible to process inspectors, diagnostic tools, audit logs, crash reports, and shell history. Prefer stdin, file descriptors, or purpose-built credential channels over putting secrets in command strings or argument arrays.
Captured stdout and stderr can contain credentials, personal data, build artifacts, or terminal-control sequences. Bound buffered output with maxBuffer, sanitize before rendering in HTML or logs, and apply retention controls to stored output.
runStream() when output may be large. Consume or redirect every piped stream so a child cannot stall indefinitely on a full pipe.Timeout and cancellation request termination
const controller = new AbortController();
const task = cmd.runPromise(command, {
signal: controller.signal,
timeout: 30_000,
killSignal: 'SIGTERM'
});
controller.abort();A timeout causes Node to request termination after the configured interval. Abort signals and child.kill() also target the immediate child according to Node and operating-system semantics. None is a guaranteed hard execution deadline, and descendant processes can survive.
- Listen for both
errorandclose. - Design a platform-specific escalation policy if termination must be enforced.
- Use external isolation—containers, job objects, cgroups, service supervisors, or restricted accounts—when the process must be contained.
No elevation is requested
node-cmd does not request administrator, root, sudo, or UAC access. Children inherit the privileges and accessible resources of the Node.js process. Run the parent with the least privilege necessary; do not treat library calls as an elevation boundary.
Review behavior on every target OS
Unix shells and Windows ComSpec differ in quoting, variable expansion, separators, built-ins, signals, executable lookup, and script-file behavior. Windows .bat and .cmd files require a shell. Test the exact command, input classes, cancellation path, output volume, and error handling on each supported operating system.
Report vulnerabilities privately
Use GitHub’s private vulnerability reporting form. Include the affected version, platform, Node version, minimal reproduction, security impact, and any known mitigations. Do not open a public issue for an unpatched vulnerability.