Found by the nightly security audit's application-security pass (see SECURITY.md → CI Validation Contract), verified by hand.
What happens
shellEscapePath picks its quoting rule from the host platform, never from the shell running in the target pane:
https://github.com/diffplug/dormouse/blob/main/lib/src/lib/shell-escape.ts#L27-L29
export function shellEscapePath(input: string): string {
return !IS_MAC && IS_WINDOWS ? shellEscapeWindows(input) : shellEscapePosix(input);
}
shellEscapeWindows wraps the path in double quotes and doubles any embedded ". That is correct for cmd.exe, which does no expansion inside double quotes. It is not correct for PowerShell, where a double-quoted string is expandable: $(...) runs a subexpression and $name interpolates.
So on Windows, dropping (or pasting) a file named
into a PowerShell pane stages the line
and the subexpression runs as soon as the user presses Enter — which they have every reason to do, since they just dropped a file in to use its path. The single caller is the drop/paste path:
https://github.com/diffplug/dormouse/blob/main/lib/src/lib/clipboard.ts#L66
const text = paths.map(shellEscapePath).join(' ') + ' ';
Severity
Low-to-moderate. It needs a Windows host, a PowerShell pane, and a file whose name the attacker controls — an unzipped archive, a shared folder, a download. Nothing is executed without the user pressing Enter. But the whole point of drag-and-drop is that the resulting line looks like an ordinary path and gets run without inspection, and a filename is exactly the kind of thing users treat as inert data.
The fix already exists one package over
dor quotes per target shell rather than per host platform, and gets PowerShell right:
https://github.com/diffplug/dormouse/blob/main/dor/src/commands/shell-quote.ts#L13-L21
The work is threading the pane's shell identity to the call site in clipboard.ts and reusing that logic instead of shellEscapePath's platform branch. Worth checking whether anything else infers a shell from process.platform.
docs/specs/mouse-and-clipboard.md owns this behavior and should be updated with the fix — it currently describes the escaping without noting that it assumes the host's default shell.
Found by the nightly security audit's
application-securitypass (see SECURITY.md → CI Validation Contract), verified by hand.What happens
shellEscapePathpicks its quoting rule from the host platform, never from the shell running in the target pane:https://github.com/diffplug/dormouse/blob/main/lib/src/lib/shell-escape.ts#L27-L29
shellEscapeWindowswraps the path in double quotes and doubles any embedded". That is correct forcmd.exe, which does no expansion inside double quotes. It is not correct for PowerShell, where a double-quoted string is expandable:$(...)runs a subexpression and$nameinterpolates.So on Windows, dropping (or pasting) a file named
into a PowerShell pane stages the line
"$(calc.exe).txt"and the subexpression runs as soon as the user presses Enter — which they have every reason to do, since they just dropped a file in to use its path. The single caller is the drop/paste path:
https://github.com/diffplug/dormouse/blob/main/lib/src/lib/clipboard.ts#L66
Severity
Low-to-moderate. It needs a Windows host, a PowerShell pane, and a file whose name the attacker controls — an unzipped archive, a shared folder, a download. Nothing is executed without the user pressing Enter. But the whole point of drag-and-drop is that the resulting line looks like an ordinary path and gets run without inspection, and a filename is exactly the kind of thing users treat as inert data.
The fix already exists one package over
dorquotes per target shell rather than per host platform, and gets PowerShell right:https://github.com/diffplug/dormouse/blob/main/dor/src/commands/shell-quote.ts#L13-L21
The work is threading the pane's shell identity to the call site in
clipboard.tsand reusing that logic instead ofshellEscapePath's platform branch. Worth checking whether anything else infers a shell fromprocess.platform.docs/specs/mouse-and-clipboard.mdowns this behavior and should be updated with the fix — it currently describes the escaping without noting that it assumes the host's default shell.