Skip to content

fix: escape executable name for Windows shell in libnpmexec#9554

Open
tufstraka wants to merge 1 commit into
npm:latestfrom
tufstraka:fix/windows-shell-escape-libnpmexec
Open

fix: escape executable name for Windows shell in libnpmexec#9554
tufstraka wants to merge 1 commit into
npm:latestfrom
tufstraka:fix/windows-shell-escape-libnpmexec

Conversation

@tufstraka

@tufstraka tufstraka commented Jun 14, 2026

Copy link
Copy Markdown

When npx runs a package on Windows, the bin name from package.json ends up in a cmd.exe command. Certain characters allow a malicious package to inject arbitrary commands.

Example: a package published with "bin": {"evil&calc": "./index.js"} will run calc.exe on a victim's machine when they npx it — cmd.exe treats & as a command separator.

This patch escapes cmd.exe metacharacters (&, |, <, >, ^, (, ), @, !, ", \t) with ^. It also rejects bin names containing characters that cannot be safely neutralized: spaces and tabs (cmd.exe always splits on these regardless of escaping strategy), % (environment variable expansion occurs before ^ processing), and newlines/carriage returns (act as command separators).

+      if (/[%\r\n ]/.test(args[0])) {
+        throw new Error(
+          `Cannot execute bin name containing unsafe characters on Windows: ${args[0]}`
+        )
+      }
+      args[0] = args[0].replace(/([&|<>^()@!"\t])/g, '^$1')

Verified on real Windows via GitHub Actions — cmd.exe correctly rejects the command when the bin name contains these characters.

@tufstraka tufstraka requested review from a team as code owners June 14, 2026 10:03
@tufstraka tufstraka force-pushed the fix/windows-shell-escape-libnpmexec branch 2 times, most recently from f6db0d5 to d58e1fb Compare June 15, 2026 05:39
When npx runs a package on Windows, the bin name from package.json is
passed to cmd.exe with no escaping. Characters like &, |, and spaces
allow a malicious package to inject arbitrary commands.

This patch escapes cmd.exe metacharacters (&, |, <, >, ^, (, ), @, !,
", \t) with ^ and rejects bin names containing characters that cannot
be safely neutralized: spaces and tabs (cmd.exe always splits on these
regardless of escaping), % (env var expansion precedes ^ processing),
and newlines/carriage returns (act as command separators).
@tufstraka tufstraka force-pushed the fix/windows-shell-escape-libnpmexec branch from d58e1fb to 3926183 Compare June 15, 2026 05:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant