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:
// 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 &:
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:
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 via CreateProcess without cmd.exe interpretation.
- Unix platforms, which used the single-quote branch of
escapeShellArg and 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: true in node:child_process calls on Windows.
- Building the argv directly and invoking the program without a shell.
- Filtering or rejecting any externally-supplied argument values that contained
cmd.exe metacharacters (& | < > ^ ! ( ) %) before passing them to spawn / spawnSync / exec.
References
Summary
Deno's
node:child_processimplementation provided anescapeShellArg()helper used when callers passedshell: truetospawn/spawnSync/execand friends. On Windows, the helper failed to quote arguments that containedcmd.exemetacharacters such as&,|,<,>,^,!,(,), and did not neutralize%(whichcmd.exeexpands 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 spawnedcmd.exeinvocation.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_processwithshell: trueran the command viacmd.exe /d /s /c "<command line>". Deno assembled that command line by joining the program name and each argument throughescapeShellArg().The vulnerable check was:
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&:The reporter confirmed this launched
calc.exeon Windows 11 with Deno 2.7.5. The same shape worked for|,<,>,^,!,(, and).A secondary defect existed even when arguments were quoted:
cmd.exeexpands%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:Observed:
calc.exelaunched as a side effect of theechocall.Impact
Any Deno program on Windows that called
child_process.spawn/spawnSync/exec(or any shell helper that funneled throughescapeShellArg) withshell: trueand 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:
shell: true(the default), which executed the program directly viaCreateProcesswithoutcmd.exeinterpretation.escapeShellArgand were already fixed under CVE-2026-27190.shell: true— those were the caller's responsibility and were never sanitized by Deno.Workarounds
Users on unpatched versions could mitigate by:
shell: trueinnode:child_processcalls on Windows.cmd.exemetacharacters (& | < > ^ ! ( ) %) before passing them tospawn/spawnSync/exec.References