Skip to content

[Security] Fix command injection in treeKill utility#7430

Open
gonzaloriestra wants to merge 1 commit intomainfrom
sentinel/fix-tree-kill-command-injection-13735669651940213355
Open

[Security] Fix command injection in treeKill utility#7430
gonzaloriestra wants to merge 1 commit intomainfrom
sentinel/fix-tree-kill-command-injection-13735669651940213355

Conversation

@gonzaloriestra
Copy link
Copy Markdown
Contributor

@gonzaloriestra gonzaloriestra commented Apr 30, 2026

WHY are these changes introduced?

treeKill in @shopify/cli-kit had a critical command injection vulnerability on Windows. The PID validation used Number.isNaN(pid) against a string, which always returns false for non-NaN string values, so malicious inputs like "1234; calc.exe" slipped through. The Windows branch then forwarded the value to child_process.exec via string concatenation, which spawns a shell and interprets the injected command.

WHAT is this pull request doing?

  • Replaces the broken Number.isNaN PID check with a strict regex (/^\d+$/) so only digit-only strings are accepted.
  • Switches the Windows taskkill invocation from child_process.exec (shell-based) to child_process.spawn with arguments passed as an array, eliminating shell interpolation.
  • Adds packages/cli-kit/src/public/node/tree-kill.test.ts with regression coverage for malicious and valid PID inputs.
  • Adds short security-focused comments at the validation and spawn sites.

How to test your changes?

treeKill is invoked when you quit shopify app dev (it tears down the dev process tree). Build the CLI, run a dev session against any sample app, and confirm a graceful shutdown:

pnpm install
pnpm shopify app dev --path <path-to-app>
# Inside the dev session, press 'q' (or Ctrl+C) and confirm the CLI exits cleanly.
# Then confirm no orphans were left behind (matches against full argv):
pgrep -fl 'app dev --path .*<path-to-app>' || echo "no orphan dev processes"

Then sanity-check the new PID validation directly. With a malicious PID it should refuse to spawn anything and surface the validation error. Run from the repo root against the built bundle:

pnpm nx build cli-kit
node -e "import('./packages/cli-kit/dist/public/node/tree-kill.js').then(({treeKill}) => treeKill('1234; calc.exe', 'SIGTERM', true, (err) => console.log(err?.message)))"
# Expect: pid must be a number

On Windows specifically, the taskkill invocation now uses spawn with array arguments instead of exec with string concatenation. Reviewers on Windows can confirm by running shopify app dev and quitting — the child tree should still terminate.

Checklist

  • I've considered possible cross-platform impacts (Mac, Linux, Windows)
  • I've considered possible documentation changes
  • I've considered analytics changes to measure impact
  • The change is user-facing — I've identified the correct bump type (patch for bug fixes · minor for new features · major for breaking changes) and added a changeset with pnpm changeset add

@gonzaloriestra gonzaloriestra requested a review from a team as a code owner April 30, 2026 00:15
@google-labs-jules
Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@github-actions github-actions Bot added cla-needed no-changelog This PR doesn't include a changeset entry. Is an internal only change not relevant to end users. labels Apr 30, 2026
@gonzaloriestra gonzaloriestra force-pushed the sentinel/fix-tree-kill-command-injection-13735669651940213355 branch from b2fd339 to 9aab38a Compare April 30, 2026 07:55
@gonzaloriestra gonzaloriestra changed the title 🛡️ Sentinel: [CRITICAL] Fix command injection in treeKill utility [Security] Fix command injection in treeKill utility Apr 30, 2026
🚨 Severity: CRITICAL
💡 Vulnerability: Command injection on Windows systems.
🎯 Impact: An attacker could execute arbitrary commands by providing a malicious PID string.
🔧 Fix:
- Replaced the broken `Number.isNaN` PID validation with a robust regex check (`/^\d+$/`).
- Replaced `child_process.exec` with `child_process.spawn` for the Windows `taskkill` command to prevent shell interpretation of arguments.
- Added security comments explaining the fixes.
✅ Verification:
- Added a new unit test file `packages/cli-kit/src/public/node/tree-kill.test.ts` to verify the fix.
- Ran `pnpm lint` and `pnpm type-check` for `@shopify/cli-kit`.

Made-with: Cursor
@gonzaloriestra gonzaloriestra force-pushed the sentinel/fix-tree-kill-command-injection-13735669651940213355 branch from 9aab38a to f4de6ef Compare April 30, 2026 08:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changelog This PR doesn't include a changeset entry. Is an internal only change not relevant to end users.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant