Skip to content

PowerShell runInTerminal does not correctly quote environment values containing single quotes #331751

Description

When VS Code constructs a PowerShell command for a Debug Adapter Protocol runInTerminal request, environment variable values are handled differently from normal command arguments.

PowerShell command arguments already use the existing shell-specific quoting helper, which escapes embedded single quotes correctly. However, environment values are currently manually wrapped in single quotes.

For example, the environment assignment is constructed in a form equivalent to:

command += `\${env:${key}}='${value}'; `;

This works for ordinary values, but a value containing a single quote produces malformed or unintended PowerShell syntax.

Example

Given an environment value such as:

hello'world

the generated command currently becomes:

${env:QUOTE}='hello'world';

For a PowerShell single-quoted string, the embedded quote should instead be doubled:

${env:QUOTE}='hello''world';

This is already how the existing PowerShell argument quoting logic handles embedded single quotes.

Relevant code

The behavior occurs in:

src/vs/workbench/contrib/debug/node/terminals.ts

inside the PowerShell handling in prepareCommand().

The relevant runInTerminal flow is:

DAP runInTerminal request
→ RawDebugSession
→ Debugger.runInTerminal
→ MainThreadDebugService
→ ExtHostDebugService.$runInTerminal
→ prepareCommand(...)
→ terminal shell integration / sendText()

Steps to reproduce

A focused unit test can reproduce the problem by calling prepareCommand() with PowerShell and an environment value containing a single quote.

For example:

prepareCommand(
    'powershell',
    [],
    false,
    undefined,
    { QUOTE: 'hello\'world' }
).trim()

Current output

${env:QUOTE}='hello'world';

Expected output

${env:QUOTE}='hello''world';

The same issue is visible with values containing multiple single quotes.

For example:

it's 'ok'

should be represented as:

${env:MULTI}='it''s ''ok''';

Expected behavior

PowerShell environment values should use the same PowerShell quoting rules as command arguments so that the original environment value is preserved exactly.

Values such as the following should all be represented correctly:

hello
hello world

hello'world
it's 'ok'

including an empty string.

Actual behavior

Environment values are manually wrapped in single quotes without escaping embedded single quotes.

As a result, values containing ' do not preserve the intended PowerShell string structure.

Proposed fix

Reuse the existing PowerShell quote() helper when constructing environment assignments instead of manually wrapping the value.

Conceptually:

- command += `\${env:${key}}='${value}'; `;
+ command += `\${env:${key}}=${quote(value)}; `;

This keeps PowerShell environment handling consistent with the existing argument quoting behavior and avoids introducing a second quoting implementation.

Regression coverage

A focused regression test covers:

  • ordinary values
  • values containing spaces
  • empty values
  • one embedded single quote
  • multiple embedded single quotes

The regression test fails with the current implementation for quoted values and passes after reusing the existing PowerShell quoting helper.

Relevant test file:

src/vs/workbench/contrib/debug/test/node/terminals.test.ts

Validation

After applying the minimal change:

powershell - quotes environment values
1 passing

The existing nearby prepareCommand test suite also passes:

Debug - prepareCommand
7 passing

The client transpilation also completes successfully:

npm run transpile-client
✓ completed successfully

Security considerations

I have not identified a separate security boundary violation from this behavior.

Normal debugging requires Workspace Trust, and the runInTerminal request originates from the active debug adapter/debug extension context.

Based on the current analysis, this appears to be a correctness and shell-command construction issue, rather than a security vulnerability.

Environment

Observed in the current VS Code development source tree on Windows with PowerShell command construction.

Metadata

Metadata

Labels

insiders-releasedPatch has been released in VS Code Insiders

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions