PT-2026-50146 · Crates.Io · Deno
Published
2026-06-16
·
Updated
2026-06-16
·
CVE-2026-49402
CVSS v3.1
8.1
High
| Vector | AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H |
Summary
Deno's
node:child process implementation provided an escapeShellArg() helper used when callers passed shell: true to spawn / spawnSync / exec and friends. On Windows, the helper failed to quote arguments that contained cmd.exe metacharacters such as &, |, <, >, ^, !, (, ), and did not neutralize % (which cmd.exe expands even inside double-quoted strings). An attacker who controlled any portion of an argument passed to such a call could inject arbitrary additional commands into the spawned cmd.exe invocation.This was the Windows counterpart to CVE-2026-27190, which fixed the same class of bug in the Unix branch of
escapeShellArg.Details
On Windows,
child process with shell: true ran the command via cmd.exe /d /s /c "<command line>". Deno assembled that command line by joining the program name and each argument through escapeShellArg().The vulnerable check was:
ts
// If no special characters, return as-is
if (!/[s"]/.test(arg)) {
return arg;
}The regex covered only whitespace, double-quote, and backslash. Any argument containing
cmd.exe-significant characters but none of those three was returned unquoted and therefore interpreted by the shell. The most straightforward exploit chained commands with &:js
import { spawnSync } from "node:child process";
spawnSync("echo", ["test&calc.exe"], { shell: true, encoding: "utf-8" });The reporter confirmed this launched
calc.exe on Windows 11 with Deno 2.7.5. The same shape worked for |, <, >, ^, !, (, and ).A secondary defect existed even when arguments were quoted:
cmd.exe expands %FOO% environment-variable references inside double-quoted strings. Without either doubling % or rejecting it, an argument like "%USERPROFILE%" leaked environment data into the command line.Proof of concept
From the report, run on Windows with Deno
< 2.7.10:js
import { spawnSync } from "node:child process";
const maliciousInput = "test&calc.exe";
const result = spawnSync("echo", [maliciousInput], {
shell: true,
encoding: "utf-8",
});
console.log(result);Observed:
calc.exe launched as a side effect of the echo call.Impact
Any Deno program on Windows that called
child process.spawn / spawnSync / exec (or any shell helper that funneled through escapeShellArg) with shell: true and incorporated untrusted input into an argument was exposed to arbitrary command execution in the context of the Deno process. The CVSS vector treated this as network-reachable / high-complexity because the typical exposure path was a Deno service accepting external input and forwarding it to a shelled-out subprocess.Not affected:
- Calls without
shell: true(the default), which executed the program directly viaCreateProcesswithoutcmd.exeinterpretation. - Unix platforms, which used the single-quote branch of
escapeShellArgand were already fixed under CVE-2026-27190. - Callers that built command strings themselves and passed them as a single string with
shell: true— those were the caller's responsibility and were never sanitized by Deno.
Workarounds
Users on unpatched versions could mitigate by:
- Avoiding
shell: trueinnode:child processcalls on Windows. - Building the argv directly and invoking the program without a shell.
- Filtering or rejecting any externally-supplied argument values that contained
cmd.exemetacharacters (& | < > ^ ! ( ) %) before passing them tospawn/spawnSync/exec.
Fix
OS Command Injection
Found an issue in the description? Have something to add? Feel free to write us 👾
Weakness Enumeration
Related Identifiers
Affected Products
Deno