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
Escaping shell arguments to exec() #143
Comments
+1 |
1 similar comment
+1 |
+10000000 |
@d11wtq we don't currently support an array syntax for Or is your concern about escaping values (such as how |
Please. Providing only a string argument here is a recipe for disaster, honestly. As pointed out, it's basically impossible to "properly" quote any arguments given. As is, |
Looks like this might be related to #103. @cscott The concern is that, under-the-hood, we rely on Node's child_process module (specifically,
Could you give an example where it's impossible to quote arguments? I thought it was just a matter of escaping the appropriate characters, i.e. Maybe it would be better to expose a function for shell-escaping? Then we can write things such as: // This gives us an alternative syntax
exec('printf "\\\\"'); // this works, but that's lots of backslashes! Very error-prone
exec(shellEscape('printf "\\"')); // this looks like the bash command: `printf "\\"`
// or, this example
ls('src/').forEach(function (fileName) {
exec('head ' + shellEscape(fileName)); // it's safe to use the output of ls() now
} |
|
Just spitballing potential issues with "just the quotes" escaping -- what happens if you follow a Unicode surrogate character with a quote. Does node/bash treat that as an actual quote, or as a invalid utf character (and replace it with a different utf character)? Is this the same on all platforms and all shells? This is just the first example I can think of---I guarantee you that if you are passing untrusted values to the shell via string concatenation and relying on naïve escaping you will find plenty of similar edge cases and surprises. This is really security 101. |
@cscott from the docs for ShellJS's
Since it says the word "command," I argue that this should, by default, behave like executing a command in the shell (we don't call them "commands" in C and other relevant languages). I interpret I'm not opposed to secure code. # in an empty directory
$ touch a.txt # creates a normal file
$ touch b.txt # again, works as expected
$ touch *.txt # does not create a file, this just updates time stamps for the other two
$ touch '*.txt' # this creates a file named *.txt
$ for k in *.txt; do echo $k; done # no quotes around $k is insecure
a.txt
b.txt
a.txt b.txt *.txt
$ for k in *.txt; do echo "$k"; done # double quotes allow $k to work sensibly
a.txt
b.txt
*.txt One thing that's unique about exec is if you try The point being, we can't just have one solution for |
Actually, a better idea would be to add an option to exec called "noGlob". When true, all characters are treated literally (as if the shell argument were wrapped in single quotes, or like an argument passed to C's execvp system call). As well as an explicit shellEscape function that prevents glob expansion on its arguments |
I'm not opposed to an `execFile` alternative. But I'd be much happier with
an option called `glob` or `shell` that enabled the dangerous functionality
for those who actually want/need it, and left most users "safe by default".
|
@cscott Here's what I'm thinking the interface should look like. exec(cmd); // this will use a default value for glob (haven't decided if that should be false or true)
exec(cmd, {glob: true}); // '*' expands like a shell glob. Other characters have special meanings
exec(cmd, {glob: false}); // ';', '*', '?', '>' are all taken literally
exec(arg1, arg2, arg3); // executes something like `'arg1' 'arg2' 'arg3'` in the shell. arg2 could have a space, and it will still count as one argument
exec(arg1, arg2, arg3, {glob: true}); // arg2 can have a space, but it will still be one argument. * is a glob character
exec(arg1, arg2, arg3, {glob: false}); // same as above, but * is a literal *. ? is a literal ?. Etc. The question remains, should this option be named Also, while we're on the subject, it may be worth considering adding a |
@nfischer: +1 on |
I've got an idea for an API: What if we did this (using ES6 string tags): shell`mycommand --opt ${unsafeVar}` That gets transpiled to: shell('mycommand --opt ', unsafeVar); (Which is a totally acceptable syntax for <ES6.) |
@cscott Although I think we may try to add in the |
I would like to see @ariporad's suggestion implemented, making multi-line scripts possible as well (I think..). |
can someone please update/resolve this issue please |
Merging into #495, which is starting to see some traction (see #866). Design doc: https://shelljs.page.link/cmd-design |
Update on this please, this is now a 4 year old bug. |
A proper solution would be to pass command line arguments as an array. Unfortunately, this is not currently possible with shelljs. See also shelljs/shelljs#143. As a workaround, surround the command with quotes to at least fix commands with spaces. Closes #50.
First of all, I just want to say thanks for writing shelljs. It cleans up my code a lot.
I need to invoke commands with
shell.exec()
, however, those commands will include some input from external sources, to be passed as arguments to system executables. Is there a "safe" way to do this? I was hoping for the classic array syntax, like:Though this doesn't seem to be implemented. It doesn't appear nodejs itself even has a shell escape function neither. Any plans on this front?
The text was updated successfully, but these errors were encountered: