Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

child_process should individually escape args[] on shell: true #29532

Closed
Artoria2e5 opened this issue Sep 12, 2019 · 3 comments
Closed

child_process should individually escape args[] on shell: true #29532

Artoria2e5 opened this issue Sep 12, 2019 · 3 comments
Labels
child_process Issues and PRs related to the child_process subsystem. stale

Comments

@Artoria2e5
Copy link

Artoria2e5 commented Sep 12, 2019

  • Version: 12.5.0, i don't care, it never worked
  • Platform: Windows, but Unix too
  • Subsystem: child_process

This is probably a design 🐛, and fixing it would require an incompatible change.

The shell: true handling of child_process joins the contents of args[] with spaces and simply sends them off to the shell. Although it is documented that shell: true is for handling globs and the like, doing so is still inconsiderate and irresponsible because devs expect some degree of safety by putting stuff in an array instead of one long string.

The problem? Well, shell: true is mandatory for running many of the .cmd shims on Windows because these things are not otherwise considered executable, so at least shell: process.platform === 'win32' is needed. And although cmd does not interpret globs, it does interpret flow control stuff like & and &&. Our linter script, set up with lint-staged, faced exactly that: someone threw in a test script with & in the filename for it to lint, and the command chopped off at that ampersand because you broke the argument separation. Yes, programming code filenames should not look like that, but neither should a spawning mechanism break!

My proposal for the issue is that nodejs should escape the contents of args indivudually (map) before joining them into a /c or -c parameter of the shell, and that the command string can instead stay as the wild-west part that people use to put complex shell-only stuff in. In other words, if command contains nothing special, spawning with shell set true or false should eventually run the exact same command, the only difference being whether another shell has been started (so things like BASH_ENV will still matter).

Implementation matters

Currently the Windows escape is written in C++ as quote_cmd_arg. Unix does not require escaping yet as its spawning mechanism already accepts an array of strings. Implementing my suggestion should mean that we should have a version of both in JavaScript:

function quote_sh_arg(arg){
    return `'${arg.replace("'", "'\\''")}'`
}
function quote_cmd_arg(arg) {
    // we don't do the verbatim case here, because we need to quote
    // (but not escape) stuff like & and | too, and that's a long list
    // to check for on indexOf()
    return `"${arg.replace('\\', '\\\\').replace('"', '\\"')}"`
}
function quote_pwsh_arg(arg) {
    // we need to specifically check for powershell now; it does -c but does
    // not quote in the same way
    return `'${arg.replace("'", "''")}'`
}

Oh that's right, we need PowerShell too. The whole shell checking will have to move a bit as well as they must be identified before quoting.

@Artoria2e5 Artoria2e5 changed the title child_process.spawn should individually escape args[] on shell: true child_process should individually escape args[] on shell: true Sep 12, 2019
Artoria2e5 added a commit to DimensionDev/Maskbook that referenced this issue Sep 12, 2019
we can node it ourselves; triggered by nodejs/node#29532
@bnoordhuis bnoordhuis added the child_process Issues and PRs related to the child_process subsystem. label Sep 12, 2019
@bnoordhuis
Copy link
Member

@Artoria2e5 Do you want to open a PR? It'd be semver-major (i.e., probably won't be released until Node.js v14.x) but it sounds like a reasonable change to me.

@Artoria2e5
Copy link
Author

@bnoordhuis Yes, I am working on it. After the test is finished I will open a PR. (They are the referenced commits you see.)

SunriseFox pushed a commit to DimensionDev/Maskbook that referenced this issue Sep 16, 2019
we can node it ourselves; triggered by nodejs/node#29532
Jack-Works pushed a commit to DimensionDev/Maskbook that referenced this issue Sep 16, 2019
we can node it ourselves; triggered by nodejs/node#29532
Artoria2e5 added a commit to Artoria2e5/node that referenced this issue Sep 18, 2019
BREAKING CHANGE: This changes the behavior of args[] in `shell: true` to
escape globs and other metacharacters. If you want to keep your scripts,
do it the proper way and stuff them in "command."

Refs: nodejs#29576
Fixes: nodejs#29532
Artoria2e5 added a commit to Artoria2e5/node that referenced this issue Jan 11, 2021
BREAKING CHANGE: This changes the behavior of args[] in `shell: true` to
escape globs and other metacharacters. If you want to keep your scripts,
do it the proper way and stuff them in "command."

Refs: nodejs#29576
Fixes: nodejs#29532
@RedYetiDev
Copy link
Member

The linked PR for this was closed several years ago. I'm closing this issue as 'Stale', but feel-free to revisit.

@RedYetiDev RedYetiDev closed this as not planned Won't fix, can't repro, duplicate, stale Jul 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
child_process Issues and PRs related to the child_process subsystem. stale
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants