fix: prevent command injection via shell metacharacters on Windows#32678
fix: prevent command injection via shell metacharacters on Windows#32678VenkatKwest wants to merge 3 commits intoangular:mainfrom
Conversation
…revent command injection Git is a native executable on Windows and does not require shell: true. Switch to array-based spawn and separate the -m flag from the commit message to prevent command injection via crafted commit messages.
Escape shell metacharacters when invoking package managers via cmd.exe instead of using shell: true with unsanitized arguments. The escape logic is based on cross-spawn's approach of directly invoking cmd.exe with properly escaped arguments and windowsVerbatimArguments: true.
There was a problem hiding this comment.
Code Review
This pull request addresses command injection vulnerabilities on Windows by removing shell: true where it's not needed and by properly escaping arguments when a shell is required.
The changes in packages/angular_devkit/schematics/tasks/repo-init/executor.ts for git commands are correct, switching to spawn with an argument array instead of a concatenated string.
The changes in packages/angular/cli/src/package-managers/host.ts for package manager commands correctly identify the need for a shell on Windows but replace the insecure shell: true with a direct call to cmd.exe. However, I've found an issue in the custom argument escaping logic. The regular expressions for escaping backslashes are different from the cross-spawn library they are based on, and one of them appears to be buggy, which could lead to incorrect escaping. I've left a comment with a suggested fix to align the implementation with cross-spawn's battle-tested approach.
Note: Security Review is unavailable for this PR.
| // Convert to string | ||
| arg = `${arg}`; | ||
|
|
There was a problem hiding this comment.
This seems redundant since the input is a string.
| // Convert to string | |
| arg = `${arg}`; |
| @@ -20,6 +20,42 @@ import { platform, tmpdir } from 'node:os'; | |||
| import { join } from 'node:path'; | |||
| import { PackageManagerError } from './error'; | |||
|
|
|||
There was a problem hiding this comment.
The below code is literally a copy and paste from cross-spawn. Please add links or re-write and mention that is was inspires from. Otherwise this cannot be merged.
alan-agius4
left a comment
There was a problem hiding this comment.
I had a chat with @clydin and actually this is not a vulnerability at all as the commit message cannot be passed via the command line and thus command injection cannot be triggered in this case.
Hence, kindly revert all the changes host.ts, can leave the cleanup in the executor.ts
Remove redundant string conversion, add proper attribution with authoritative Microsoft documentation link, and refactor to avoid multiple re-assignments as suggested by reviewer.
|
Thanks for the review, @alan-agius4! I've addressed all your feedback:
|
Description
This PR fixes command injection vulnerabilities on Windows in two files:
1.
executor.ts(git spawn)shell: true— git is a native.exeand doesn't need itspawn(\git ${args.join(' ')}`)tospawn('git', args)`-mflag from commit message:['commit', '-m', message]instead of['commit', \-m "${message}"`]`2.
host.ts(package manager spawn).cmdscripts on Windows and need a shellshell: truewith unsanitized argument concatenation, we now invokecmd.exe /d /s /cdirectly with properly escaped argumentswindowsVerbatimArguments: trueto prevent Node.js from re-escapingTesting
Verified on Windows 11 (Node v25.6.0):
& echo INJECTED,& echo PWNED > file) are blockedshell: truepattern confirmed vulnerable (control test)Fixes #32509