== How to fix it in Node.js

=== Code examples

include::../../common/fix/code-rationale.adoc[]

==== Noncompliant code example

[source,javascript,diff-id=1,diff-type=noncompliant]
----
const { execSync } = require('child_process')

cmd = req.query.cmd
execSync(cmd) // Noncompliant
----

==== Compliant solution

[source,javascript,diff-id=1,diff-type=compliant]
----
const { spawnSync } = require('child_process')

const cmdId = parseInt(req.query.cmdId)
let host = req.query.host
host = typeof host === "string"? host : "example.org"

const allowedCommands = [
    {exe:"/bin/ping", args:["-c","1","--"]},
    {exe:"/bin/host", args:["--"]}
]
const cmd = allowedCommands[cmdId]
spawnSync(cmd.exe, cmd.args.concat(host))
----

=== How does this work?

include::../../common/fix/introduction.adoc[]

include::../../common/fix/pre-approved-list.adoc[]

In the example compliant code, a static list of trusted commands is used. Users are only allowed to
submit an index in this array in place of a full command name.

:sanitizationLib: child_process.spawn

include::../../common/fix/sanitize-meta-characters.adoc[]

In the example compliant code, the `spawn` function from `child_process` is used in place of its less
secure `exec` counterpart. It accepts command arguments as an array and
performs a proper escaping of its element before building the command line to
run.

include::../../common/fix/shell_integration.adoc[]

The `spawn` function that is used in the example compliant code disables shell integration by default.

=== Pitfalls

include::../common/pitfalls/loose-typing.adoc[]

In the above compliant code example, the ambiguous `concat` function is used.
However, a type check has been introduced to prevent any unexpected issue.
