Does this issue occur when all extensions are disabled?: Yes
Version: 1.116.0-insider (system setup)
Commit: 1ec46de
Date: 2026-04-09T09:55:17-07:00
Electron: 39.8.5
ElectronBuildId: 13703022
Chromium: 142.0.7444.265
Node.js: 22.22.1
V8: 14.2.231.22-electron.0
OS: Windows_NT x64 10.0.26200
This is regarding the follow suspicious code, which does not appear to properly handle converting an executable/command path and an arguments array (which should always be assumed to not contain quoting/escaping, as that is a 'shell command line' concept), to a shell command line:
|
// executeCommand(commandLine: string): vscode.TerminalShellExecution; |
|
// executeCommand(executable: string, args: string[]): vscode.TerminalShellExecution; |
|
executeCommand(commandLineOrExecutable: string, args?: string[]): vscode.TerminalShellExecution { |
|
if (!supportsExecuteCommandApi) { |
|
throw new Error('This terminal does not support the executeCommand API.'); |
|
} |
|
let commandLineValue = commandLineOrExecutable; |
|
if (args) { |
|
for (const arg of args) { |
|
const wrapInQuotes = !arg.match(/["'`]/) && arg.match(/\s/); |
|
if (wrapInQuotes) { |
|
commandLineValue += ` "${arg}"`; |
|
} else { |
|
commandLineValue += ` ${arg}`; |
|
} |
|
} |
|
} |
Some related background:
Everyone quotes command line arguments the wrong way
How Command Line Parameters Are Parsed
CommandLineToArgvW function (shellapi.h)
AI generated bug details:
Bug: TerminalShellIntegration.executeCommand(executable, args) serializes structured input into shell text using naive quoting
Summary
The TerminalShellIntegration.executeCommand(executable, args) overload looks like it accepts structured argv-style input, but the current implementation in src/vs/workbench/api/common/extHostTerminalShellIntegration.ts simply builds a single shell command line string:
let commandLineValue = commandLineOrExecutable;
if (args) {
for (const arg of args) {
const wrapInQuotes = !arg.match(/["'`]/) && arg.match(/\s/);
if (wrapInQuotes) {
commandLineValue += ` "${arg}"`;
} else {
commandLineValue += ` ${arg}`;
}
}
}
This means the executable token is copied verbatim and the arguments are appended with only a minimal quoting heuristic before the whole string is reparsed by the active shell.
Problem
This serialization is shell-agnostic and incomplete:
- the command/executable portion is not quoted or escaped at all,
- arguments are only quoted in a narrow whitespace-only case,
- literal quote characters inside arguments are not escaped,
- shell metacharacters like
;, &, |, <, >, `, and $() are not handled safely,
- and quoting/escaping rules differ significantly across shells and platforms (
zsh, bash, pwsh, cmd, etc.).
As a result, this API overload does not preserve structured input reliably. Both the executable token and the argument boundaries can change when the shell reparses the constructed command line.
Why this matters
An API shaped like:
executeCommand(executable: string, args: string[])
strongly suggests that executable and each item in args are treated as literal tokens. But the current behavior is really “best-effort shell string construction”, which is a weaker and more error-prone contract.
At minimum, arguments containing literal double quotes are mishandled. More broadly, this can lead to incorrect argv at the target process or unexpected shell interpretation.
Relevant code path
InternalTerminalShellIntegration.executeCommand(...) builds commandLineValue
MainThreadTerminalShellIntegration.$executeCommand(...) forwards the string
TerminalInstance.runCommand(...) / sendText(...) writes it into the PTY
- the active shell reparses that text and launches the subprocess
So this API does not directly spawn a process from an argument array; it sends a command line string to the shell.
Example problematic inputs
These should be treated as literal tokens, but may be misparsed by the shell:
- executable:
'/tmp/My Tool'
- args:
['a"b']
- args:
['a b"c']
- args:
['foo;bar']
- args:
['$(uname)']
Expected behavior
Either:
- the
executeCommand(executable, args) overload should use shell/platform-specific escaping that preserves the executable token and argument boundaries as accurately as possible for the active shell,
or
- the API/docs should explicitly state that this overload is only a best-effort conversion to shell text and cannot guarantee exact
argv preservation.
At minimum, literal quotes inside arguments should be escaped correctly, and the executable token should not be emitted verbatim when it requires quoting.
Does this issue occur when all extensions are disabled?: Yes
Version: 1.116.0-insider (system setup)
Commit: 1ec46de
Date: 2026-04-09T09:55:17-07:00
Electron: 39.8.5
ElectronBuildId: 13703022
Chromium: 142.0.7444.265
Node.js: 22.22.1
V8: 14.2.231.22-electron.0
OS: Windows_NT x64 10.0.26200
This is regarding the follow suspicious code, which does not appear to properly handle converting an executable/command path and an arguments array (which should always be assumed to not contain quoting/escaping, as that is a 'shell command line' concept), to a shell command line:
vscode/src/vs/workbench/api/common/extHostTerminalShellIntegration.ts
Lines 207 to 223 in c5729b1
Some related background:
Everyone quotes command line arguments the wrong way
How Command Line Parameters Are Parsed
CommandLineToArgvW function (shellapi.h)
AI generated bug details:
Bug:
TerminalShellIntegration.executeCommand(executable, args)serializes structured input into shell text using naive quotingSummary
The
TerminalShellIntegration.executeCommand(executable, args)overload looks like it accepts structuredargv-style input, but the current implementation insrc/vs/workbench/api/common/extHostTerminalShellIntegration.tssimply builds a single shell command line string:This means the executable token is copied verbatim and the arguments are appended with only a minimal quoting heuristic before the whole string is reparsed by the active shell.
Problem
This serialization is shell-agnostic and incomplete:
;,&,|,<,>,`, and$()are not handled safely,zsh,bash,pwsh,cmd, etc.).As a result, this API overload does not preserve structured input reliably. Both the executable token and the argument boundaries can change when the shell reparses the constructed command line.
Why this matters
An API shaped like:
strongly suggests that
executableand each item inargsare treated as literal tokens. But the current behavior is really “best-effort shell string construction”, which is a weaker and more error-prone contract.At minimum, arguments containing literal double quotes are mishandled. More broadly, this can lead to incorrect
argvat the target process or unexpected shell interpretation.Relevant code path
InternalTerminalShellIntegration.executeCommand(...)buildscommandLineValueMainThreadTerminalShellIntegration.$executeCommand(...)forwards the stringTerminalInstance.runCommand(...)/sendText(...)writes it into the PTYSo this API does not directly spawn a process from an argument array; it sends a command line string to the shell.
Example problematic inputs
These should be treated as literal tokens, but may be misparsed by the shell:
'/tmp/My Tool'['a"b']['a b"c']['foo;bar']['$(uname)']Expected behavior
Either:
executeCommand(executable, args)overload should use shell/platform-specific escaping that preserves the executable token and argument boundaries as accurately as possible for the active shell,or
argvpreservation.At minimum, literal quotes inside arguments should be escaped correctly, and the executable token should not be emitted verbatim when it requires quoting.