Repository navigation
[BUG] Inline terminal spawns user-configured shell path without validation #1743
Description
What happens
With the inline terminal active, commands run through execa, and when the execaShellPath setting is set its raw value goes straight to the spawn as the command shell (src/integrations/terminal/ExecaTerminalProcess.ts:44: shell: BaseTerminal.getExecaShellPath() || getShell()). Whatever string the setting holds, including a path the codebase's own shell allowlist rejects, is spawned without validation.
All line references are to main at 01928c3c4, extension version 3.82.2.
Code path
getShell()(src/utils/shell.ts) is the codebase's shell resolution. It prefersexecaShellPath, falls back through detected terminal and environment defaults (VS Code terminal profile,os.userInfo(),COMSPEC/SHELL), then validates the candidate againstSHELL_ALLOWLIST, substituting a platform-safe fallback when it fails the check (isShellAllowed,getSafeFallbackShell). The allowlist's comment inshell.tsdescribes it as protection against arbitrary command execution.- The spawn short-circuits that control. When
execaShellPathis set, the||operator takes the raw value andgetShell()is never called at the spawn site, so the configured string is handed to execa without ever passing the allowlist check. SettingexecaShellPathtoC:\Tools\Git\bin\bash.exe, a path the allowlist does not contain, makes inline-terminal commands run in that executable. - No webview control writes
execaShellPathtoday, but the plumbing is live: the setting is declared inpackages/types/src/global-settings.ts:227, carried as an extension-state key inpackages/types/src/vscode-extension-host.ts:305, and applied insrc/core/webview/webviewMessageHandler.ts:834, which stores the value onBaseTerminalwithout checking it. - The current spawn test pins the unvalidated behavior:
"should use execaShellPath when set"(src/integrations/terminal/__tests__/ExecaTerminalProcess.spec.ts:104) asserts that execa receives the configured string verbatim.
Acceptance criteria
- The shell handed to execa at the spawn site is validated before use: reject
execaShellPathagainst the shell allowlist and either fail closed or fall back to the platform-safe default instead of spawning the raw configured path.getShell()already prefersexecaShellPathand then gates the result, so passing its return value at the spawn site in place of the raw value achieves this and keeps today's behavior for every allowlisted value. - A regression test proves that with
execaShellPathset to a non-allowlisted path, execa receives the fallback and not the configured path, and the test named above is updated to match. - A Windows regression test pins the spawn behavior when
execaShellPathis unset andCOMSPECis set to a non-allowlisted path: execa must receive the platform-safe default rather than the custom executable, giving documented, tested fallback behavior for the Windows shell-resolution edge cases. No test on main pins what execa receives in that case;ExecaTerminalProcess.spec.tshas noCOMSPECcases. - Unset or allowlisted
execaShellPath, and unset or allowlistedCOMSPEC, keep their current behavior. The fix needs no POSIX-specific handling; the VS Code integrated terminal path is untouched. - A comment at the spawn site states the invariant: the executable passed to execa is a validated shell.
Scope
This issue covers the inline terminal's spawn site only. Out of scope: changes to shell detection (the resolution order inside getShell() and its VS Code terminal-profile handling), changes to what the system prompt reports about the shell or environment, and honoring the VS Code terminal-profile override for the inline terminal.
Activity
[-]Inline terminal spawns user-configured shell path without validation[/-][+][BUG] Inline terminal spawns user-configured shell path without validation[/+]DaubnerF commentedon Sep 21, 2026
claiming