Skip to content

Potential fix for code scanning alert no. 8: Unsafe shell command constructed from library input#610

Merged
cute-omega merged 1 commit intomasterfrom
alert-autofix-8
Apr 25, 2026
Merged

Potential fix for code scanning alert no. 8: Unsafe shell command constructed from library input#610
cute-omega merged 1 commit intomasterfrom
alert-autofix-8

Conversation

@cute-omega
Copy link
Copy Markdown
Collaborator

Potential fix for https://github.com/docmirror/dev-sidecar/security/code-scanning/8

Best fix: avoid building a shell command string from cmds in the Windows non-ps branch. Execute commands without shell interpretation by using execFile and explicit argument arrays.

In this file, the safest minimal change is:

  1. Add a helper to execute cmd.exe safely with /d /s /c and a single provided command string argument (no concatenation across user-provided commands).
  2. In WindowsSystemShell.exec non-ps branch, run chcp 65001 as a fixed command first, then execute each cmd separately through the helper, collecting the last output (matching current return behavior of last command output).
  3. Keep existing behavior for ps mode and other platforms unchanged.

This removes the vulnerable concatenation at line 64 and avoids passing a composed shell string to childProcess.exec.

Suggested fixes powered by Copilot Autofix. Review carefully before merging.

…structed from library input

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
@cute-omega cute-omega marked this pull request as ready for review April 25, 2026 17:43
Copilot AI review requested due to automatic review settings April 25, 2026 17:43
@cute-omega cute-omega merged commit 688c31b into master Apr 25, 2026
13 checks passed
@cute-omega cute-omega deleted the alert-autofix-8 branch April 25, 2026 17:43
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR attempts to address code-scanning alert #8 by removing Windows non-PowerShell command concatenation (&& chaining) and executing commands via execFile instead of exec.

Changes:

  • Replaced the Windows non-ps branch from building a single chained command string to executing chcp 65001 and then each command individually.
  • Added a childExecCmdWindows helper that runs cmd.exe via childProcess.execFile and preserves existing logging/error behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +72 to +80
function childExecCmdWindows (cmd, options = {}) {
return new Promise((resolve, reject) => {
const execOptions = { ...options }
delete execOptions.type
delete execOptions.printErrorLog

log.info('shell:', cmd)
childProcess.execFile('cmd.exe', ['/d', '/s', '/c', cmd], execOptions, (error, stdout, stderr) => {
if (error) {
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description says this avoids shell interpretation by using execFile with explicit argument arrays, but this helper still runs user-provided cmd through cmd.exe /c, which does interpret shell metacharacters (&, |, redirection, etc.). If cmd can contain untrusted input, this remains command-injection prone; the safer approach is to execFile the target executable directly with an argv array (or restrict/escape allowed commands/args before invoking cmd.exe).

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +67
await childExecCmdWindows('chcp 65001', args)
let ret
for (const cmd of cmds) {
compose += ` && ${cmd}`
ret = await childExecCmdWindows(cmd, args)
}
// compose += '&& exit'
return await childExec(compose, args)
return ret
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the non-ps branch, ret will be undefined when cmds is an empty array, whereas previously the function would return the (post-processed) output from running chcp 65001. Consider returning an explicit empty string (or the chcp output) when there are no commands to preserve a consistent return type.

Copilot uses AI. Check for mistakes.
Comment on lines +62 to 66
await childExecCmdWindows('chcp 65001', args)
let ret
for (const cmd of cmds) {
compose += ` && ${cmd}`
ret = await childExecCmdWindows(cmd, args)
}
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

chcp 65001 is now executed in a separate cmd.exe process, so the code page change won’t persist for the subsequent command executions (each childExecCmdWindows call spawns a new process). This likely regresses the original intent of ensuring UTF-8 output for the actual commands; consider running the chcp 65001 step in the same invocation as each command (or otherwise ensuring the code page is set for the process that runs the command).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants