From a20ca78599ecb6736c67a7714326eb86fdaf0e11 Mon Sep 17 00:00:00 2001 From: amammad Date: Fri, 22 Sep 2023 19:23:34 +1000 Subject: [PATCH 01/10] V1 --- javascript/ql/lib/javascript.qll | 1 + .../semmle/javascript/frameworks/Execa.qll | 234 ++++++++++++++++++ .../frameworks/Execa/Execa.expected | 68 +++++ .../library-tests/frameworks/Execa/Execa.ql | 12 + .../library-tests/frameworks/Execa/tst.js | 49 ++++ 5 files changed, 364 insertions(+) create mode 100644 javascript/ql/lib/semmle/javascript/frameworks/Execa.qll create mode 100644 javascript/ql/test/library-tests/frameworks/Execa/Execa.expected create mode 100644 javascript/ql/test/library-tests/frameworks/Execa/Execa.ql create mode 100644 javascript/ql/test/library-tests/frameworks/Execa/tst.js diff --git a/javascript/ql/lib/javascript.qll b/javascript/ql/lib/javascript.qll index 07fb759bd655..238bd870a905 100644 --- a/javascript/ql/lib/javascript.qll +++ b/javascript/ql/lib/javascript.qll @@ -123,6 +123,7 @@ import semmle.javascript.frameworks.Request import semmle.javascript.frameworks.RxJS import semmle.javascript.frameworks.ServerLess import semmle.javascript.frameworks.ShellJS +import semmle.javascript.frameworks.Execa import semmle.javascript.frameworks.Snapdragon import semmle.javascript.frameworks.SystemCommandExecutors import semmle.javascript.frameworks.SQL diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll b/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll new file mode 100644 index 000000000000..fe654a287f5c --- /dev/null +++ b/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll @@ -0,0 +1,234 @@ +/** + * Models the `execa` library in terms of `FileSystemAccess` and `SystemCommandExecution`. + */ + +import javascript +import semmle.javascript.security.dataflow.RequestForgeryCustomizations +import semmle.javascript.security.dataflow.UrlConcatenation + +/** + * Provide model for [Execa](https://github.com/sindresorhus/execa) package + */ +module Execa { + /** + * The Execa input file option + */ + class ExecaRead extends FileSystemReadAccess, DataFlow::Node { + API::Node execaNode; + + ExecaRead() { + ( + execaNode = API::moduleImport("execa").getMember("$").getParameter(0) + or + execaNode = + API::moduleImport("execa") + .getMember(["execa", "execaCommand", "execaCommandSync", "execaSync"]) + .getParameter([0, 1, 2]) + ) and + this = execaNode.asSink() + } + + // data is the output of a command so IDK how it can be implemented + override DataFlow::Node getADataNode() { none() } + + override DataFlow::Node getAPathArgument() { + result = execaNode.getMember("inputFile").asSink() + } + } + + /** + * A call to `execa.execa` or `execa.execaSync` + */ + class ExecaCall extends API::CallNode { + string name; + + ExecaCall() { + this = API::moduleImport("execa").getMember("execa").getACall() and + name = "execa" + or + this = API::moduleImport("execa").getMember("execaSync").getACall() and + name = "execaSync" + } + + /** Gets the name of the exported function, such as `rm` in `shelljs.rm()`. */ + string getName() { result = name } + } + + /** + * The system command execution nodes for `execa.execa` or `execa.execaSync` functions + */ + class ExecaExec extends SystemCommandExecution, ExecaCall { + ExecaExec() { name = ["execa", "execaSync"] } + + override DataFlow::Node getACommandArgument() { result = this.getArgument(0) } + + override predicate isShellInterpreted(DataFlow::Node arg) { + // if shell: true then first and second args are sinks + // options can be third argument + arg = [this.getArgument(0), this.getParameter(1).getUnknownMember().asSink()] and + isExecaShellEnable(this.getParameter(2)) + or + // options can be second argument + arg = this.getArgument(0) and + isExecaShellEnable(this.getParameter(1)) + } + + override predicate isSync() { name = "execaSync" } + + override DataFlow::Node getOptionsArg() { + result = this.getLastArgument() and result.asExpr() instanceof ObjectExpr + } + } + + /** + * A call to `execa.$` or `execa.$.sync` tag functions + */ + private class ExecaScriptExpr extends DataFlow::ExprNode { + string name; + + ExecaScriptExpr() { + this.asExpr() = + [ + API::moduleImport("execa").getMember("$"), + API::moduleImport("execa").getMember("$").getReturn() + ].getAValueReachableFromSource().asExpr() and + name = "ASync" + or + this.asExpr() = + [ + API::moduleImport("execa").getMember("$").getMember("sync"), + API::moduleImport("execa").getMember("$").getMember("sync").getReturn() + ].getAValueReachableFromSource().asExpr() and + name = "Sync" + } + + /** Gets the name of the exported function, such as `rm` in `shelljs.rm()`. */ + string getName() { result = name } + } + + /** + * The system command execution nodes for `execa.$` or `execa.$.sync` tag functions + */ + class ExecaScriptEec extends SystemCommandExecution, ExecaScriptExpr { + ExecaScriptEec() { name = ["Sync", "ASync"] } + + override DataFlow::Node getACommandArgument() { + result.asExpr() = templateLiteralChildAsSink(this.asExpr()).getChildExpr(0) + } + + override predicate isShellInterpreted(DataFlow::Node arg) { + // $({shell: true})`${sink} ${sink} .. ${sink}` + // ISSUE: $`cmd args` I can't reach the tag function argument easily + exists(TemplateLiteral tmpL | templateLiteralChildAsSink(this.asExpr()) = tmpL | + arg.asExpr() = tmpL.getAChildExpr+() and + isExecaShellEnableWithExpr(this.asExpr().(CallExpr).getArgument(0)) + ) + } + + override DataFlow::Node getArgumentList() { + // $`${Can Not Be sink} ${sink} .. ${sink}` + exists(TemplateLiteral tmpL | templateLiteralChildAsSink(this.asExpr()) = tmpL | + result.asExpr() = tmpL.getAChildExpr+() and + not result.asExpr() = tmpL.getChildExpr(0) + ) + } + + override predicate isSync() { name = "Sync" } + + override DataFlow::Node getOptionsArg() { + result = this.asExpr().getAChildExpr*().flow() and result.asExpr() instanceof ObjectExpr + } + } + + /** + * A call to `execa.execaCommandSync` or `execa.execaCommand` + */ + private class ExecaCommandCall extends API::CallNode { + string name; + + ExecaCommandCall() { + this = API::moduleImport("execa").getMember("execaCommandSync").getACall() and + name = "execaCommandSync" + or + this = API::moduleImport("execa").getMember("execaCommand").getACall() and + name = "execaCommand" + } + + /** Gets the name of the exported function, such as `rm` in `shelljs.rm()`. */ + string getName() { result = name } + } + + /** + * The system command execution nodes for `execa.execaCommand` or `execa.execaCommandSync` functions + */ + class ExecaCommandExec2 extends SystemCommandExecution, DataFlow::CallNode { + ExecaCommandExec2() { this = API::moduleImport("execa").getMember("execaCommand").getACall() } + + override DataFlow::Node getACommandArgument() { result = this.getArgument(0) } + + override DataFlow::Node getArgumentList() { result = this.getArgument(0) } + + override predicate isShellInterpreted(DataFlow::Node arg) { arg = this.getArgument(0) } + + override predicate isSync() { none() } + + override DataFlow::Node getOptionsArg() { result = this } + } + + /** + * The system command execution nodes for `execa.execaCommand` or `execa.execaCommandSync` functions + */ + class ExecaCommandExec extends SystemCommandExecution, ExecaCommandCall { + ExecaCommandExec() { name = ["execaCommand", "execaCommandSync"] } + + override DataFlow::Node getACommandArgument() { + result = this.(DataFlow::CallNode).getArgument(0) + } + + override DataFlow::Node getArgumentList() { + // execaCommand("echo " + sink); + // execaCommand(`echo ${sink}`); + result.asExpr() = this.getParameter(0).asSink().asExpr().getAChildExpr+() and + not result.asExpr() = this.getArgument(0).asExpr().getChildExpr(0) + } + + override predicate isShellInterpreted(DataFlow::Node arg) { + // execaCommandSync(sink1 + sink2, {shell: true}) + arg.asExpr() = this.getArgument(0).asExpr().getAChildExpr+() and + isExecaShellEnable(this.getParameter(1)) + or + // there is only one argument that is constructed in previous nodes, + // it makes sanitizing really hard to select whether it is vulnerable to argument injection or not + arg = this.getParameter(0).asSink() and + not exists(this.getArgument(0).asExpr().getChildExpr(1)) + } + + override predicate isSync() { name = "execaCommandSync" } + + override DataFlow::Node getOptionsArg() { + result = this.getLastArgument() and result.asExpr() instanceof ObjectExpr + } + } + + // Holds if left parameter is the left child of a template literal and returns the template literal + private TemplateLiteral templateLiteralChildAsSink(Expr left) { + exists(TaggedTemplateExpr parent | + parent.getTemplate() = result and + left = parent.getChildExpr(0) + ) + } + + // Holds whether Execa has shell enabled options or not, get Parameter responsible for options + private predicate isExecaShellEnable(API::Node n) { + n.getMember("shell").asSink().asExpr().(BooleanLiteral).getValue() = "true" + } + + // Holds whether Execa has shell enabled options or not, get Parameter responsible for options + private predicate isExecaShellEnableWithExpr(Expr n) { + exists(ObjectExpr o, Property p | o = n.getAChildExpr*() | + o.getAChild() = p and + p.getAChild().(Label).getName() = "shell" and + p.getAChild().(Literal).getValue() = "true" + ) + } +} diff --git a/javascript/ql/test/library-tests/frameworks/Execa/Execa.expected b/javascript/ql/test/library-tests/frameworks/Execa/Execa.expected new file mode 100644 index 000000000000..a99d033b6efc --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Execa/Execa.expected @@ -0,0 +1,68 @@ +test_FileSystemAccess +| tst.js:18:9:18:23 | { shell: true } | +| tst.js:20:9:20:24 | { shell: false } | +| tst.js:24:13:24:22 | 'aCommand' | +| tst.js:24:25:24:36 | ['example1'] | +| tst.js:26:13:26:18 | 'echo' | +| tst.js:26:21:26:32 | ['example1'] | +| tst.js:28:13:28:47 | 'echo e ... ple 11' | +| tst.js:28:50:28:64 | { shell: true } | +| tst.js:29:13:29:29 | 'echo example 10' | +| tst.js:29:32:29:52 | ['; ech ... le 11'] | +| tst.js:29:55:29:69 | { shell: true } | +| tst.js:32:11:32:16 | 'echo' | +| tst.js:32:19:32:35 | ['example5 sync'] | +| tst.js:34:20:34:42 | "echo " ... gument" | +| tst.js:35:20:35:52 | `echo $ ... ndSync` | +| tst.js:37:18:37:20 | arg | +| tst.js:39:18:39:39 | "echo 1 ... echo 2" | +| tst.js:39:42:39:56 | { shell: true } | +| tst.js:45:9:45:27 | { inputFile: file } | +| tst.js:46:13:46:17 | 'cat' | +| tst.js:46:20:46:38 | { inputFile: file } | +| tst.js:47:13:47:18 | 'echo' | +| tst.js:47:21:47:32 | ['example2'] | +| tst.js:48:13:48:18 | 'echo' | +| tst.js:48:21:48:32 | ['example3'] | +| tst.js:49:13:49:18 | 'echo' | +| tst.js:49:21:49:32 | ['example4'] | +| tst.js:49:35:49:47 | { all: true } | +test_MissingFileSystemAccess +| tst.js:43:35:43:38 | file | +| tst.js:47:46:47:49 | file | +| tst.js:48:46:48:49 | file | +| tst.js:49:58:49:61 | file | +test_SystemCommandExecution +| tst.js:1:71:1:71 | $ | +| tst.js:4:7:4:7 | $ | +| tst.js:5:7:5:7 | $ | +| tst.js:6:1:6:1 | $ | +| tst.js:6:1:6:6 | $.sync | +| tst.js:10:7:10:7 | $ | +| tst.js:12:7:12:7 | $ | +| tst.js:13:1:13:1 | $ | +| tst.js:13:1:13:6 | $.sync | +| tst.js:15:1:15:1 | $ | +| tst.js:15:1:15:6 | $.sync | +| tst.js:16:7:16:7 | $ | +| tst.js:18:7:18:7 | $ | +| tst.js:18:7:18:24 | $({ shell: true }) | +| tst.js:20:7:20:7 | $ | +| tst.js:20:7:20:25 | $({ shell: false }) | +| tst.js:24:7:24:37 | execa(' ... ple1']) | +| tst.js:26:7:26:33 | execa(' ... ple1']) | +| tst.js:28:7:28:65 | execa(' ... true }) | +| tst.js:29:7:29:70 | execa(' ... true }) | +| tst.js:32:1:32:36 | execaSy ... sync']) | +| tst.js:34:7:34:43 | execaCo ... ument") | +| tst.js:35:7:35:53 | execaCo ... dSync`) | +| tst.js:37:1:37:21 | execaCo ... nc(arg) | +| tst.js:39:1:39:57 | execaCo ... true }) | +| tst.js:43:7:43:7 | $ | +| tst.js:45:7:45:7 | $ | +| tst.js:45:7:45:28 | $({ inp ... file }) | +| tst.js:46:7:46:39 | execa(' ... file }) | +| tst.js:47:7:47:33 | execa(' ... ple2']) | +| tst.js:48:7:48:33 | execa(' ... ple3']) | +| tst.js:49:7:49:48 | execa(' ... true }) | +test_FileNameSource diff --git a/javascript/ql/test/library-tests/frameworks/Execa/Execa.ql b/javascript/ql/test/library-tests/frameworks/Execa/Execa.ql new file mode 100644 index 000000000000..42858633cd3a --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Execa/Execa.ql @@ -0,0 +1,12 @@ +import javascript + +query predicate test_FileSystemAccess(FileSystemAccess access) { any() } + +query predicate test_MissingFileSystemAccess(VarAccess var) { + var.getName().matches("file%") and + not exists(FileSystemAccess access | access.getAPathArgument().asExpr() = var) +} + +query predicate test_SystemCommandExecution(SystemCommandExecution exec) { any() } + +query predicate test_FileNameSource(FileNameSource exec) { any() } diff --git a/javascript/ql/test/library-tests/frameworks/Execa/tst.js b/javascript/ql/test/library-tests/frameworks/Execa/tst.js new file mode 100644 index 000000000000..0e657d421a24 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Execa/tst.js @@ -0,0 +1,49 @@ +import { execa, execaSync, execaCommand, execaCommandSync, execaNode, $ } from 'execa'; + +// Node.js scripts +await $`echo example1`.pipeStderr(`tmp`); +await $`echo ${"example2"}`.pipeStderr(`tmp`); +$.sync`echo example2 sync` +// Multiple arguments +const args = ["arg:" + arg, 'example3', '&', 'rainbows!']; +// GOOD +await $`${arg} sth`; +// GOOD only one command can be executed +await $`${arg}`; +$.sync`${arg}` +// BAD argument injection +$.sync`echo ${args} ${args}` +await $`echo ${["-a", "-lps"]}` +// if shell: true then all inputs except first are dangerous +await $({ shell: true })`echo example6 ${";echo example6 > tmpdir/example6"}` +// GOOD +await $({ shell: false })`echo example6 ${";echo example6 > tmpdir/example6"}` + +// execa +// GOOD +await execa('aCommand', ['example1']); +// BAD argument injection +await execa('echo', ['example1']); +// BAD shell is enable +await execa('echo example 10 ; echo example 11', { shell: true }); +await execa('echo example 10', ['; echo example 11'], { shell: true }); + +// BAD argument injection +execaSync('echo', ['example5 sync']); +// BAD argument injection +await execaCommand("echo " + "badArgument"); +await execaCommand(`echo ${"arg1"} execaCommandSync`); +// bad totally controllable argument +execaCommandSync(arg); +// BAD shell is enable +execaCommandSync("echo 1 " + "; echo 2", { shell: true }); + +// FileSystemAccess +// Piping stdout to a file +await $`echo example8`.pipeStdout(file) +// Piping stdin from a file +await $({ inputFile: file })`cat` +await execa('cat', { inputFile: file }); +await execa('echo', ['example2']).pipeStdout(file); +await execa('echo', ['example3']).pipeStderr(file); +await execa('echo', ['example4'], { all: true }).pipeAll(file); From 2c74dc23c9240d728e4e350f93254ba53c627984 Mon Sep 17 00:00:00 2001 From: amammad Date: Fri, 22 Sep 2023 20:00:36 +1000 Subject: [PATCH 02/10] add second order command execution sinks to tests --- .../frameworks/Execa/Execa.expected | 122 +++++++++--------- .../library-tests/frameworks/Execa/tst.js | 16 ++- 2 files changed, 71 insertions(+), 67 deletions(-) diff --git a/javascript/ql/test/library-tests/frameworks/Execa/Execa.expected b/javascript/ql/test/library-tests/frameworks/Execa/Execa.expected index a99d033b6efc..c4e12a8dca6e 100644 --- a/javascript/ql/test/library-tests/frameworks/Execa/Execa.expected +++ b/javascript/ql/test/library-tests/frameworks/Execa/Execa.expected @@ -1,68 +1,68 @@ test_FileSystemAccess -| tst.js:18:9:18:23 | { shell: true } | -| tst.js:20:9:20:24 | { shell: false } | -| tst.js:24:13:24:22 | 'aCommand' | -| tst.js:24:25:24:36 | ['example1'] | -| tst.js:26:13:26:18 | 'echo' | -| tst.js:26:21:26:32 | ['example1'] | -| tst.js:28:13:28:47 | 'echo e ... ple 11' | -| tst.js:28:50:28:64 | { shell: true } | -| tst.js:29:13:29:29 | 'echo example 10' | -| tst.js:29:32:29:52 | ['; ech ... le 11'] | -| tst.js:29:55:29:69 | { shell: true } | -| tst.js:32:11:32:16 | 'echo' | -| tst.js:32:19:32:35 | ['example5 sync'] | -| tst.js:34:20:34:42 | "echo " ... gument" | -| tst.js:35:20:35:52 | `echo $ ... ndSync` | -| tst.js:37:18:37:20 | arg | -| tst.js:39:18:39:39 | "echo 1 ... echo 2" | -| tst.js:39:42:39:56 | { shell: true } | -| tst.js:45:9:45:27 | { inputFile: file } | -| tst.js:46:13:46:17 | 'cat' | -| tst.js:46:20:46:38 | { inputFile: file } | -| tst.js:47:13:47:18 | 'echo' | -| tst.js:47:21:47:32 | ['example2'] | -| tst.js:48:13:48:18 | 'echo' | -| tst.js:48:21:48:32 | ['example3'] | -| tst.js:49:13:49:18 | 'echo' | -| tst.js:49:21:49:32 | ['example4'] | -| tst.js:49:35:49:47 | { all: true } | +| tst.js:22:9:22:23 | { shell: true } | +| tst.js:24:9:24:24 | { shell: false } | +| tst.js:28:13:28:22 | 'aCommand' | +| tst.js:28:25:28:36 | ['example1'] | +| tst.js:30:13:30:17 | 'git' | +| tst.js:30:20:30:31 | ['example1'] | +| tst.js:32:13:32:47 | 'echo e ... ple 11' | +| tst.js:32:50:32:64 | { shell: true } | +| tst.js:33:13:33:29 | 'echo example 10' | +| tst.js:33:32:33:52 | ['; ech ... le 11'] | +| tst.js:33:55:33:69 | { shell: true } | +| tst.js:36:11:36:16 | 'echo' | +| tst.js:36:19:36:35 | ['example5 sync'] | +| tst.js:38:20:38:41 | "git " ... gument" | +| tst.js:39:20:39:51 | `git ${ ... ndSync` | +| tst.js:41:18:41:20 | arg | +| tst.js:43:18:43:39 | "echo 1 ... echo 2" | +| tst.js:43:42:43:56 | { shell: true } | +| tst.js:49:9:49:27 | { inputFile: file } | +| tst.js:50:13:50:17 | 'cat' | +| tst.js:50:20:50:38 | { inputFile: file } | +| tst.js:51:13:51:18 | 'echo' | +| tst.js:51:21:51:32 | ['example2'] | +| tst.js:52:13:52:18 | 'echo' | +| tst.js:52:21:52:32 | ['example3'] | +| tst.js:53:13:53:18 | 'echo' | +| tst.js:53:21:53:32 | ['example4'] | +| tst.js:53:35:53:47 | { all: true } | test_MissingFileSystemAccess -| tst.js:43:35:43:38 | file | -| tst.js:47:46:47:49 | file | -| tst.js:48:46:48:49 | file | -| tst.js:49:58:49:61 | file | +| tst.js:47:35:47:38 | file | +| tst.js:51:46:51:49 | file | +| tst.js:52:46:52:49 | file | +| tst.js:53:58:53:61 | file | test_SystemCommandExecution | tst.js:1:71:1:71 | $ | -| tst.js:4:7:4:7 | $ | -| tst.js:5:7:5:7 | $ | -| tst.js:6:1:6:1 | $ | -| tst.js:6:1:6:6 | $.sync | -| tst.js:10:7:10:7 | $ | -| tst.js:12:7:12:7 | $ | -| tst.js:13:1:13:1 | $ | -| tst.js:13:1:13:6 | $.sync | -| tst.js:15:1:15:1 | $ | -| tst.js:15:1:15:6 | $.sync | +| tst.js:7:7:7:7 | $ | +| tst.js:9:7:9:7 | $ | +| tst.js:10:1:10:1 | $ | +| tst.js:10:1:10:6 | $.sync | +| tst.js:14:7:14:7 | $ | | tst.js:16:7:16:7 | $ | -| tst.js:18:7:18:7 | $ | -| tst.js:18:7:18:24 | $({ shell: true }) | +| tst.js:17:1:17:1 | $ | +| tst.js:17:1:17:6 | $.sync | +| tst.js:19:1:19:1 | $ | +| tst.js:19:1:19:6 | $.sync | | tst.js:20:7:20:7 | $ | -| tst.js:20:7:20:25 | $({ shell: false }) | -| tst.js:24:7:24:37 | execa(' ... ple1']) | -| tst.js:26:7:26:33 | execa(' ... ple1']) | -| tst.js:28:7:28:65 | execa(' ... true }) | -| tst.js:29:7:29:70 | execa(' ... true }) | -| tst.js:32:1:32:36 | execaSy ... sync']) | -| tst.js:34:7:34:43 | execaCo ... ument") | -| tst.js:35:7:35:53 | execaCo ... dSync`) | -| tst.js:37:1:37:21 | execaCo ... nc(arg) | -| tst.js:39:1:39:57 | execaCo ... true }) | -| tst.js:43:7:43:7 | $ | -| tst.js:45:7:45:7 | $ | -| tst.js:45:7:45:28 | $({ inp ... file }) | -| tst.js:46:7:46:39 | execa(' ... file }) | -| tst.js:47:7:47:33 | execa(' ... ple2']) | -| tst.js:48:7:48:33 | execa(' ... ple3']) | -| tst.js:49:7:49:48 | execa(' ... true }) | +| tst.js:22:7:22:7 | $ | +| tst.js:22:7:22:24 | $({ shell: true }) | +| tst.js:24:7:24:7 | $ | +| tst.js:24:7:24:25 | $({ shell: false }) | +| tst.js:28:7:28:37 | execa(' ... ple1']) | +| tst.js:30:7:30:32 | execa(' ... ple1']) | +| tst.js:32:7:32:65 | execa(' ... true }) | +| tst.js:33:7:33:70 | execa(' ... true }) | +| tst.js:36:1:36:36 | execaSy ... sync']) | +| tst.js:38:7:38:42 | execaCo ... ument") | +| tst.js:39:7:39:52 | execaCo ... dSync`) | +| tst.js:41:1:41:21 | execaCo ... nc(arg) | +| tst.js:43:1:43:57 | execaCo ... true }) | +| tst.js:47:7:47:7 | $ | +| tst.js:49:7:49:7 | $ | +| tst.js:49:7:49:28 | $({ inp ... file }) | +| tst.js:50:7:50:39 | execa(' ... file }) | +| tst.js:51:7:51:33 | execa(' ... ple2']) | +| tst.js:52:7:52:33 | execa(' ... ple3']) | +| tst.js:53:7:53:48 | execa(' ... true }) | test_FileNameSource diff --git a/javascript/ql/test/library-tests/frameworks/Execa/tst.js b/javascript/ql/test/library-tests/frameworks/Execa/tst.js index 0e657d421a24..e31fa07dbb43 100644 --- a/javascript/ql/test/library-tests/frameworks/Execa/tst.js +++ b/javascript/ql/test/library-tests/frameworks/Execa/tst.js @@ -1,8 +1,12 @@ import { execa, execaSync, execaCommand, execaCommandSync, execaNode, $ } from 'execa'; +const arg = process.argv[0]; + // Node.js scripts +// GOOD await $`echo example1`.pipeStderr(`tmp`); -await $`echo ${"example2"}`.pipeStderr(`tmp`); +// BAD argument injection +await $`ssh ${"example2"}`.pipeStderr(`tmp`); $.sync`echo example2 sync` // Multiple arguments const args = ["arg:" + arg, 'example3', '&', 'rainbows!']; @@ -12,8 +16,8 @@ await $`${arg} sth`; await $`${arg}`; $.sync`${arg}` // BAD argument injection -$.sync`echo ${args} ${args}` -await $`echo ${["-a", "-lps"]}` +$.sync`git ${args} ${args}` +await $`git ${["-o", "-lps"]}` // if shell: true then all inputs except first are dangerous await $({ shell: true })`echo example6 ${";echo example6 > tmpdir/example6"}` // GOOD @@ -23,7 +27,7 @@ await $({ shell: false })`echo example6 ${";echo example6 > tmpdir/example6"}` // GOOD await execa('aCommand', ['example1']); // BAD argument injection -await execa('echo', ['example1']); +await execa('git', ['example1']); // BAD shell is enable await execa('echo example 10 ; echo example 11', { shell: true }); await execa('echo example 10', ['; echo example 11'], { shell: true }); @@ -31,8 +35,8 @@ await execa('echo example 10', ['; echo example 11'], { shell: true }); // BAD argument injection execaSync('echo', ['example5 sync']); // BAD argument injection -await execaCommand("echo " + "badArgument"); -await execaCommand(`echo ${"arg1"} execaCommandSync`); +await execaCommand("git " + "badArgument"); +await execaCommand(`git ${"arg1"} execaCommandSync`); // bad totally controllable argument execaCommandSync(arg); // BAD shell is enable From 7d961e1af228f321761a28c89e7609749c171fe7 Mon Sep 17 00:00:00 2001 From: amammad <77095239+amammad@users.noreply.github.com> Date: Fri, 6 Oct 2023 16:07:10 +0200 Subject: [PATCH 03/10] do review improvements --- .../semmle/javascript/frameworks/Execa.qll | 138 +++---- .../library-tests/frameworks/Execa/Execa.ql | 12 - .../CWE-022/TaintedPath/TaintedPath.expected | 381 ++++++++++++++++++ .../Security/CWE-022/TaintedPath/execa.js | 19 + .../CommandInjection.expected | 122 ++++++ .../CWE-078/CommandInjection/execa.js | 25 ++ 6 files changed, 616 insertions(+), 81 deletions(-) delete mode 100644 javascript/ql/test/library-tests/frameworks/Execa/Execa.ql create mode 100644 javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/execa.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/execa.js diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll b/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll index fe654a287f5c..5cfecc1c814d 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll @@ -4,35 +4,46 @@ import javascript import semmle.javascript.security.dataflow.RequestForgeryCustomizations -import semmle.javascript.security.dataflow.UrlConcatenation /** * Provide model for [Execa](https://github.com/sindresorhus/execa) package */ module Execa { /** - * The Execa input file option + * The Execa input file read and output file write */ - class ExecaRead extends FileSystemReadAccess, DataFlow::Node { - API::Node execaNode; + class ExecaFileSystemAccess extends FileSystemReadAccess, DataFlow::Node { + API::Node execaArg; + boolean isPipedToFile; - ExecaRead() { + ExecaFileSystemAccess() { ( - execaNode = API::moduleImport("execa").getMember("$").getParameter(0) + execaArg = API::moduleImport("execa").getMember("$").getParameter(0) and + isPipedToFile = false or - execaNode = + execaArg = API::moduleImport("execa") .getMember(["execa", "execaCommand", "execaCommandSync", "execaSync"]) - .getParameter([0, 1, 2]) + .getParameter([0, 1, 2]) and + isPipedToFile = false + or + execaArg = + API::moduleImport("execa") + .getMember(["execa", "execaCommand", "execaCommandSync", "execaSync"]) + .getReturn() + .getMember(["pipeStdout", "pipeAll", "pipeStderr"]) + .getParameter(0) and + isPipedToFile = true ) and - this = execaNode.asSink() + this = execaArg.asSink() } - // data is the output of a command so IDK how it can be implemented override DataFlow::Node getADataNode() { none() } override DataFlow::Node getAPathArgument() { - result = execaNode.getMember("inputFile").asSink() + result = execaArg.getMember("inputFile").asSink() and isPipedToFile = false + or + result = execaArg.asSink() and isPipedToFile = true } } @@ -40,25 +51,22 @@ module Execa { * A call to `execa.execa` or `execa.execaSync` */ class ExecaCall extends API::CallNode { - string name; + boolean isSync; ExecaCall() { this = API::moduleImport("execa").getMember("execa").getACall() and - name = "execa" + isSync = false or this = API::moduleImport("execa").getMember("execaSync").getACall() and - name = "execaSync" + isSync = true } - - /** Gets the name of the exported function, such as `rm` in `shelljs.rm()`. */ - string getName() { result = name } } /** * The system command execution nodes for `execa.execa` or `execa.execaSync` functions */ class ExecaExec extends SystemCommandExecution, ExecaCall { - ExecaExec() { name = ["execa", "execaSync"] } + ExecaExec() { isSync = [false, true] } override DataFlow::Node getACommandArgument() { result = this.getArgument(0) } @@ -73,7 +81,15 @@ module Execa { isExecaShellEnable(this.getParameter(1)) } - override predicate isSync() { name = "execaSync" } + override DataFlow::Node getArgumentList() { + // execa(cmd, [arg]); + exists(DataFlow::Node arg | arg = this.getArgument(1) | + // if it is a object then it is a option argument not command argument + result = arg and not arg.asExpr() instanceof ObjectExpr + ) + } + + override predicate isSync() { isSync = true } override DataFlow::Node getOptionsArg() { result = this.getLastArgument() and result.asExpr() instanceof ObjectExpr @@ -84,7 +100,7 @@ module Execa { * A call to `execa.$` or `execa.$.sync` tag functions */ private class ExecaScriptExpr extends DataFlow::ExprNode { - string name; + boolean isSync; ExecaScriptExpr() { this.asExpr() = @@ -92,51 +108,53 @@ module Execa { API::moduleImport("execa").getMember("$"), API::moduleImport("execa").getMember("$").getReturn() ].getAValueReachableFromSource().asExpr() and - name = "ASync" + isSync = false or this.asExpr() = [ API::moduleImport("execa").getMember("$").getMember("sync"), API::moduleImport("execa").getMember("$").getMember("sync").getReturn() ].getAValueReachableFromSource().asExpr() and - name = "Sync" + isSync = true } - - /** Gets the name of the exported function, such as `rm` in `shelljs.rm()`. */ - string getName() { result = name } } /** * The system command execution nodes for `execa.$` or `execa.$.sync` tag functions */ class ExecaScriptEec extends SystemCommandExecution, ExecaScriptExpr { - ExecaScriptEec() { name = ["Sync", "ASync"] } + ExecaScriptEec() { isSync = [false, true] } override DataFlow::Node getACommandArgument() { - result.asExpr() = templateLiteralChildAsSink(this.asExpr()).getChildExpr(0) + exists(TemplateLiteral tl | isFirstTaggedTemplateParameter(this.asExpr(), tl) | + result.asExpr() = tl.getChildExpr(0) and + not result.asExpr().mayHaveStringValue(" ") // exclude whitespace + ) } override predicate isShellInterpreted(DataFlow::Node arg) { - // $({shell: true})`${sink} ${sink} .. ${sink}` + // $({shell: true})`${cmd} ${arg0} ... ${arg1}` // ISSUE: $`cmd args` I can't reach the tag function argument easily - exists(TemplateLiteral tmpL | templateLiteralChildAsSink(this.asExpr()) = tmpL | - arg.asExpr() = tmpL.getAChildExpr+() and - isExecaShellEnableWithExpr(this.asExpr().(CallExpr).getArgument(0)) + exists(TemplateLiteral tmpL | isFirstTaggedTemplateParameter(this.asExpr(), tmpL) | + arg.asExpr() = tmpL.getAChildExpr() and + isExecaShellEnableWithExpr(this.asExpr().(CallExpr).getArgument(0)) and + not arg.asExpr().mayHaveStringValue(" ") // exclude whitespace ) } override DataFlow::Node getArgumentList() { - // $`${Can Not Be sink} ${sink} .. ${sink}` - exists(TemplateLiteral tmpL | templateLiteralChildAsSink(this.asExpr()) = tmpL | - result.asExpr() = tmpL.getAChildExpr+() and - not result.asExpr() = tmpL.getChildExpr(0) + // $`${cmd} ${arg0} ... ${argn}` + exists(TemplateLiteral tmpL | isFirstTaggedTemplateParameter(this.asExpr(), tmpL) | + result.asExpr() = tmpL.getAChildExpr() and + not result.asExpr() = tmpL.getChildExpr(0) and + not result.asExpr().mayHaveStringValue(" ") // exclude whitespace ) } - override predicate isSync() { name = "Sync" } + override predicate isSync() { isSync = true } override DataFlow::Node getOptionsArg() { - result = this.asExpr().getAChildExpr*().flow() and result.asExpr() instanceof ObjectExpr + result = this.asExpr().getAChildExpr().flow() and result.asExpr() instanceof ObjectExpr } } @@ -144,56 +162,35 @@ module Execa { * A call to `execa.execaCommandSync` or `execa.execaCommand` */ private class ExecaCommandCall extends API::CallNode { - string name; + boolean isSync; ExecaCommandCall() { this = API::moduleImport("execa").getMember("execaCommandSync").getACall() and - name = "execaCommandSync" + isSync = true or this = API::moduleImport("execa").getMember("execaCommand").getACall() and - name = "execaCommand" + isSync = false } - - /** Gets the name of the exported function, such as `rm` in `shelljs.rm()`. */ - string getName() { result = name } - } - - /** - * The system command execution nodes for `execa.execaCommand` or `execa.execaCommandSync` functions - */ - class ExecaCommandExec2 extends SystemCommandExecution, DataFlow::CallNode { - ExecaCommandExec2() { this = API::moduleImport("execa").getMember("execaCommand").getACall() } - - override DataFlow::Node getACommandArgument() { result = this.getArgument(0) } - - override DataFlow::Node getArgumentList() { result = this.getArgument(0) } - - override predicate isShellInterpreted(DataFlow::Node arg) { arg = this.getArgument(0) } - - override predicate isSync() { none() } - - override DataFlow::Node getOptionsArg() { result = this } } /** * The system command execution nodes for `execa.execaCommand` or `execa.execaCommandSync` functions */ class ExecaCommandExec extends SystemCommandExecution, ExecaCommandCall { - ExecaCommandExec() { name = ["execaCommand", "execaCommandSync"] } + ExecaCommandExec() { isSync = [false, true] } override DataFlow::Node getACommandArgument() { result = this.(DataFlow::CallNode).getArgument(0) } override DataFlow::Node getArgumentList() { - // execaCommand("echo " + sink); - // execaCommand(`echo ${sink}`); - result.asExpr() = this.getParameter(0).asSink().asExpr().getAChildExpr+() and + // execaCommand(`${cmd} ${arg}`); + result.asExpr() = this.getParameter(0).asSink().asExpr().getAChildExpr() and not result.asExpr() = this.getArgument(0).asExpr().getChildExpr(0) } override predicate isShellInterpreted(DataFlow::Node arg) { - // execaCommandSync(sink1 + sink2, {shell: true}) + // execaCommandSync(`${cmd} ${arg}`, {shell: true}) arg.asExpr() = this.getArgument(0).asExpr().getAChildExpr+() and isExecaShellEnable(this.getParameter(1)) or @@ -203,7 +200,7 @@ module Execa { not exists(this.getArgument(0).asExpr().getChildExpr(1)) } - override predicate isSync() { name = "execaCommandSync" } + override predicate isSync() { isSync = true } override DataFlow::Node getOptionsArg() { result = this.getLastArgument() and result.asExpr() instanceof ObjectExpr @@ -211,14 +208,17 @@ module Execa { } // Holds if left parameter is the left child of a template literal and returns the template literal - private TemplateLiteral templateLiteralChildAsSink(Expr left) { + private predicate isFirstTaggedTemplateParameter(Expr left, TemplateLiteral templateLiteral) { exists(TaggedTemplateExpr parent | - parent.getTemplate() = result and + templateLiteral = parent.getTemplate() and left = parent.getChildExpr(0) ) } - // Holds whether Execa has shell enabled options or not, get Parameter responsible for options + /** + * Holds whether Execa has shell enabled options or not, get Parameter responsible for options + */ + pragma[inline] private predicate isExecaShellEnable(API::Node n) { n.getMember("shell").asSink().asExpr().(BooleanLiteral).getValue() = "true" } diff --git a/javascript/ql/test/library-tests/frameworks/Execa/Execa.ql b/javascript/ql/test/library-tests/frameworks/Execa/Execa.ql deleted file mode 100644 index 42858633cd3a..000000000000 --- a/javascript/ql/test/library-tests/frameworks/Execa/Execa.ql +++ /dev/null @@ -1,12 +0,0 @@ -import javascript - -query predicate test_FileSystemAccess(FileSystemAccess access) { any() } - -query predicate test_MissingFileSystemAccess(VarAccess var) { - var.getName().matches("file%") and - not exists(FileSystemAccess access | access.getAPathArgument().asExpr() = var) -} - -query predicate test_SystemCommandExecution(SystemCommandExecution exec) { any() } - -query predicate test_FileNameSource(FileNameSource exec) { any() } diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected index 2d1692dce00e..a5e6653291ac 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected @@ -1535,6 +1535,159 @@ nodes | TaintedPath.js:214:35:214:38 | path | | TaintedPath.js:214:35:214:38 | path | | TaintedPath.js:214:35:214:38 | path | +| execa.js:6:9:6:64 | filePath | +| execa.js:6:9:6:64 | filePath | +| execa.js:6:9:6:64 | filePath | +| execa.js:6:9:6:64 | filePath | +| execa.js:6:9:6:64 | filePath | +| execa.js:6:9:6:64 | filePath | +| execa.js:6:9:6:64 | filePath | +| execa.js:6:9:6:64 | filePath | +| execa.js:6:9:6:64 | filePath | +| execa.js:6:9:6:64 | filePath | +| execa.js:6:9:6:64 | filePath | +| execa.js:6:9:6:64 | filePath | +| execa.js:6:9:6:64 | filePath | +| execa.js:6:9:6:64 | filePath | +| execa.js:6:9:6:64 | filePath | +| execa.js:6:9:6:64 | filePath | +| execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:30:6:36 | req.url | +| execa.js:6:30:6:36 | req.url | +| execa.js:6:30:6:36 | req.url | +| execa.js:6:30:6:36 | req.url | +| execa.js:6:30:6:36 | req.url | +| execa.js:9:26:9:33 | filePath | +| execa.js:9:26:9:33 | filePath | +| execa.js:9:26:9:33 | filePath | +| execa.js:9:26:9:33 | filePath | +| execa.js:9:26:9:33 | filePath | +| execa.js:9:26:9:33 | filePath | +| execa.js:9:26:9:33 | filePath | +| execa.js:9:26:9:33 | filePath | +| execa.js:9:26:9:33 | filePath | +| execa.js:9:26:9:33 | filePath | +| execa.js:9:26:9:33 | filePath | +| execa.js:9:26:9:33 | filePath | +| execa.js:9:26:9:33 | filePath | +| execa.js:9:26:9:33 | filePath | +| execa.js:9:26:9:33 | filePath | +| execa.js:9:26:9:33 | filePath | +| execa.js:9:26:9:33 | filePath | +| execa.js:12:37:12:44 | filePath | +| execa.js:12:37:12:44 | filePath | +| execa.js:12:37:12:44 | filePath | +| execa.js:12:37:12:44 | filePath | +| execa.js:12:37:12:44 | filePath | +| execa.js:12:37:12:44 | filePath | +| execa.js:12:37:12:44 | filePath | +| execa.js:12:37:12:44 | filePath | +| execa.js:12:37:12:44 | filePath | +| execa.js:12:37:12:44 | filePath | +| execa.js:12:37:12:44 | filePath | +| execa.js:12:37:12:44 | filePath | +| execa.js:12:37:12:44 | filePath | +| execa.js:12:37:12:44 | filePath | +| execa.js:12:37:12:44 | filePath | +| execa.js:12:37:12:44 | filePath | +| execa.js:12:37:12:44 | filePath | +| execa.js:15:50:15:57 | filePath | +| execa.js:15:50:15:57 | filePath | +| execa.js:15:50:15:57 | filePath | +| execa.js:15:50:15:57 | filePath | +| execa.js:15:50:15:57 | filePath | +| execa.js:15:50:15:57 | filePath | +| execa.js:15:50:15:57 | filePath | +| execa.js:15:50:15:57 | filePath | +| execa.js:15:50:15:57 | filePath | +| execa.js:15:50:15:57 | filePath | +| execa.js:15:50:15:57 | filePath | +| execa.js:15:50:15:57 | filePath | +| execa.js:15:50:15:57 | filePath | +| execa.js:15:50:15:57 | filePath | +| execa.js:15:50:15:57 | filePath | +| execa.js:15:50:15:57 | filePath | +| execa.js:15:50:15:57 | filePath | +| execa.js:18:62:18:69 | filePath | +| execa.js:18:62:18:69 | filePath | +| execa.js:18:62:18:69 | filePath | +| execa.js:18:62:18:69 | filePath | +| execa.js:18:62:18:69 | filePath | +| execa.js:18:62:18:69 | filePath | +| execa.js:18:62:18:69 | filePath | +| execa.js:18:62:18:69 | filePath | +| execa.js:18:62:18:69 | filePath | +| execa.js:18:62:18:69 | filePath | +| execa.js:18:62:18:69 | filePath | +| execa.js:18:62:18:69 | filePath | +| execa.js:18:62:18:69 | filePath | +| execa.js:18:62:18:69 | filePath | +| execa.js:18:62:18:69 | filePath | +| execa.js:18:62:18:69 | filePath | +| execa.js:18:62:18:69 | filePath | | express.js:8:20:8:32 | req.query.bar | | express.js:8:20:8:32 | req.query.bar | | express.js:8:20:8:32 | req.query.bar | @@ -6635,6 +6788,230 @@ edges | TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | | TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | | TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | +| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | +| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | +| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | +| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | +| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | +| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | +| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | +| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | +| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | +| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | +| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | +| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | +| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | +| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | +| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | +| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | +| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | +| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | +| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | | express.js:8:20:8:32 | req.query.bar | express.js:8:20:8:32 | req.query.bar | | handlebars.js:10:51:10:58 | filePath | handlebars.js:11:32:11:39 | filePath | | handlebars.js:10:51:10:58 | filePath | handlebars.js:11:32:11:39 | filePath | @@ -10345,6 +10722,10 @@ edges | TaintedPath.js:212:31:212:34 | path | TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:212:31:212:34 | path | This path depends on a $@. | TaintedPath.js:211:24:211:30 | req.url | user-provided value | | TaintedPath.js:213:45:213:48 | path | TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:213:45:213:48 | path | This path depends on a $@. | TaintedPath.js:211:24:211:30 | req.url | user-provided value | | TaintedPath.js:214:35:214:38 | path | TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:214:35:214:38 | path | This path depends on a $@. | TaintedPath.js:211:24:211:30 | req.url | user-provided value | +| execa.js:9:26:9:33 | filePath | execa.js:6:30:6:36 | req.url | execa.js:9:26:9:33 | filePath | This path depends on a $@. | execa.js:6:30:6:36 | req.url | user-provided value | +| execa.js:12:37:12:44 | filePath | execa.js:6:30:6:36 | req.url | execa.js:12:37:12:44 | filePath | This path depends on a $@. | execa.js:6:30:6:36 | req.url | user-provided value | +| execa.js:15:50:15:57 | filePath | execa.js:6:30:6:36 | req.url | execa.js:15:50:15:57 | filePath | This path depends on a $@. | execa.js:6:30:6:36 | req.url | user-provided value | +| execa.js:18:62:18:69 | filePath | execa.js:6:30:6:36 | req.url | execa.js:18:62:18:69 | filePath | This path depends on a $@. | execa.js:6:30:6:36 | req.url | user-provided value | | express.js:8:20:8:32 | req.query.bar | express.js:8:20:8:32 | req.query.bar | express.js:8:20:8:32 | req.query.bar | This path depends on a $@. | express.js:8:20:8:32 | req.query.bar | user-provided value | | handlebars.js:11:32:11:39 | filePath | handlebars.js:29:46:29:60 | req.params.path | handlebars.js:11:32:11:39 | filePath | This path depends on a $@. | handlebars.js:29:46:29:60 | req.params.path | user-provided value | | handlebars.js:15:25:15:32 | filePath | handlebars.js:43:15:43:29 | req.params.path | handlebars.js:15:25:15:32 | filePath | This path depends on a $@. | handlebars.js:43:15:43:29 | req.params.path | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/execa.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/execa.js new file mode 100644 index 000000000000..b246f6c384ef --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/execa.js @@ -0,0 +1,19 @@ +import { execa, $ } from 'execa'; +import http from 'node:http' +import url from 'url' + +http.createServer(async function (req, res) { + let filePath = url.parse(req.url, true).query["filePath"][0]; + + // Piping to stdin from a file + await $({ inputFile: filePath })`cat` // NOT OK + + // Piping to stdin from a file + await execa('cat', { inputFile: filePath }); // NOT OK + + // Piping Stdout to file + await execa('echo', ['example3']).pipeStdout(filePath); // NOT OK + + // Piping all of command output to file + await execa('echo', ['example4'], { all: true }).pipeAll(filePath); // NOT OK +}); \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/CommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/CommandInjection.expected index fb8bc60e6736..02f1ccf774de 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/CommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/CommandInjection.expected @@ -103,6 +103,55 @@ nodes | execSeries.js:18:34:18:40 | req.url | | execSeries.js:19:12:19:16 | [cmd] | | execSeries.js:19:13:19:15 | cmd | +| execa.js:6:9:6:54 | cmd | +| execa.js:6:15:6:38 | url.par ... , true) | +| execa.js:6:15:6:44 | url.par ... ).query | +| execa.js:6:15:6:51 | url.par ... ["cmd"] | +| execa.js:6:15:6:54 | url.par ... md"][0] | +| execa.js:6:25:6:31 | req.url | +| execa.js:6:25:6:31 | req.url | +| execa.js:7:9:7:51 | arg | +| execa.js:7:15:7:38 | url.par ... , true) | +| execa.js:7:15:7:44 | url.par ... ).query | +| execa.js:7:15:7:51 | url.par ... ["arg"] | +| execa.js:7:25:7:31 | req.url | +| execa.js:7:25:7:31 | req.url | +| execa.js:9:15:9:17 | cmd | +| execa.js:9:15:9:17 | cmd | +| execa.js:10:14:10:16 | cmd | +| execa.js:10:14:10:16 | cmd | +| execa.js:11:32:11:34 | cmd | +| execa.js:11:32:11:34 | cmd | +| execa.js:12:33:12:35 | cmd | +| execa.js:12:33:12:35 | cmd | +| execa.js:14:17:14:19 | cmd | +| execa.js:14:17:14:19 | cmd | +| execa.js:15:17:15:19 | cmd | +| execa.js:15:17:15:19 | cmd | +| execa.js:16:17:16:19 | cmd | +| execa.js:16:17:16:19 | cmd | +| execa.js:17:17:17:19 | cmd | +| execa.js:17:17:17:19 | cmd | +| execa.js:18:15:18:17 | cmd | +| execa.js:18:15:18:17 | cmd | +| execa.js:19:15:19:17 | cmd | +| execa.js:19:15:19:17 | cmd | +| execa.js:21:24:21:26 | cmd | +| execa.js:21:24:21:32 | cmd + arg | +| execa.js:21:24:21:32 | cmd + arg | +| execa.js:21:30:21:32 | arg | +| execa.js:22:22:22:24 | cmd | +| execa.js:22:22:22:30 | cmd + arg | +| execa.js:22:22:22:30 | cmd + arg | +| execa.js:22:28:22:30 | arg | +| execa.js:23:24:23:26 | cmd | +| execa.js:23:24:23:32 | cmd + arg | +| execa.js:23:24:23:32 | cmd + arg | +| execa.js:23:30:23:32 | arg | +| execa.js:24:22:24:24 | cmd | +| execa.js:24:22:24:30 | cmd + arg | +| execa.js:24:22:24:30 | cmd + arg | +| execa.js:24:28:24:30 | arg | | form-parsers.js:9:8:9:39 | "touch ... nalname | | form-parsers.js:9:8:9:39 | "touch ... nalname | | form-parsers.js:9:19:9:26 | req.file | @@ -286,6 +335,61 @@ edges | execSeries.js:18:34:18:40 | req.url | execSeries.js:18:13:18:47 | require ... , true) | | execSeries.js:19:12:19:16 | [cmd] | execSeries.js:13:19:13:26 | commands | | execSeries.js:19:13:19:15 | cmd | execSeries.js:19:12:19:16 | [cmd] | +| execa.js:6:9:6:54 | cmd | execa.js:9:15:9:17 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:9:15:9:17 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:10:14:10:16 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:10:14:10:16 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:11:32:11:34 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:11:32:11:34 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:12:33:12:35 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:12:33:12:35 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:14:17:14:19 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:14:17:14:19 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:15:17:15:19 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:15:17:15:19 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:16:17:16:19 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:16:17:16:19 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:17:17:17:19 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:17:17:17:19 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:18:15:18:17 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:18:15:18:17 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:19:15:19:17 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:19:15:19:17 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:21:24:21:26 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:22:22:22:24 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:23:24:23:26 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:24:22:24:24 | cmd | +| execa.js:6:15:6:38 | url.par ... , true) | execa.js:6:15:6:44 | url.par ... ).query | +| execa.js:6:15:6:44 | url.par ... ).query | execa.js:6:15:6:51 | url.par ... ["cmd"] | +| execa.js:6:15:6:51 | url.par ... ["cmd"] | execa.js:6:15:6:54 | url.par ... md"][0] | +| execa.js:6:15:6:54 | url.par ... md"][0] | execa.js:6:9:6:54 | cmd | +| execa.js:6:25:6:31 | req.url | execa.js:6:15:6:38 | url.par ... , true) | +| execa.js:6:25:6:31 | req.url | execa.js:6:15:6:38 | url.par ... , true) | +| execa.js:7:9:7:51 | arg | execa.js:21:30:21:32 | arg | +| execa.js:7:9:7:51 | arg | execa.js:22:28:22:30 | arg | +| execa.js:7:9:7:51 | arg | execa.js:23:30:23:32 | arg | +| execa.js:7:9:7:51 | arg | execa.js:24:28:24:30 | arg | +| execa.js:7:15:7:38 | url.par ... , true) | execa.js:7:15:7:44 | url.par ... ).query | +| execa.js:7:15:7:44 | url.par ... ).query | execa.js:7:15:7:51 | url.par ... ["arg"] | +| execa.js:7:15:7:51 | url.par ... ["arg"] | execa.js:7:9:7:51 | arg | +| execa.js:7:25:7:31 | req.url | execa.js:7:15:7:38 | url.par ... , true) | +| execa.js:7:25:7:31 | req.url | execa.js:7:15:7:38 | url.par ... , true) | +| execa.js:21:24:21:26 | cmd | execa.js:21:24:21:32 | cmd + arg | +| execa.js:21:24:21:26 | cmd | execa.js:21:24:21:32 | cmd + arg | +| execa.js:21:30:21:32 | arg | execa.js:21:24:21:32 | cmd + arg | +| execa.js:21:30:21:32 | arg | execa.js:21:24:21:32 | cmd + arg | +| execa.js:22:22:22:24 | cmd | execa.js:22:22:22:30 | cmd + arg | +| execa.js:22:22:22:24 | cmd | execa.js:22:22:22:30 | cmd + arg | +| execa.js:22:28:22:30 | arg | execa.js:22:22:22:30 | cmd + arg | +| execa.js:22:28:22:30 | arg | execa.js:22:22:22:30 | cmd + arg | +| execa.js:23:24:23:26 | cmd | execa.js:23:24:23:32 | cmd + arg | +| execa.js:23:24:23:26 | cmd | execa.js:23:24:23:32 | cmd + arg | +| execa.js:23:30:23:32 | arg | execa.js:23:24:23:32 | cmd + arg | +| execa.js:23:30:23:32 | arg | execa.js:23:24:23:32 | cmd + arg | +| execa.js:24:22:24:24 | cmd | execa.js:24:22:24:30 | cmd + arg | +| execa.js:24:22:24:24 | cmd | execa.js:24:22:24:30 | cmd + arg | +| execa.js:24:28:24:30 | arg | execa.js:24:22:24:30 | cmd + arg | +| execa.js:24:28:24:30 | arg | execa.js:24:22:24:30 | cmd + arg | | form-parsers.js:9:19:9:26 | req.file | form-parsers.js:9:19:9:39 | req.fil ... nalname | | form-parsers.js:9:19:9:26 | req.file | form-parsers.js:9:19:9:39 | req.fil ... nalname | | form-parsers.js:9:19:9:39 | req.fil ... nalname | form-parsers.js:9:8:9:39 | "touch ... nalname | @@ -391,6 +495,24 @@ edges | exec-sh2.js:10:12:10:57 | cp.spaw ... ptions) | exec-sh2.js:14:25:14:31 | req.url | exec-sh2.js:10:40:10:46 | command | This command line depends on a $@. | exec-sh2.js:14:25:14:31 | req.url | user-provided value | | exec-sh.js:15:12:15:61 | cp.spaw ... ptions) | exec-sh.js:19:25:19:31 | req.url | exec-sh.js:15:44:15:50 | command | This command line depends on a $@. | exec-sh.js:19:25:19:31 | req.url | user-provided value | | execSeries.js:14:41:14:47 | command | execSeries.js:18:34:18:40 | req.url | execSeries.js:14:41:14:47 | command | This command line depends on a $@. | execSeries.js:18:34:18:40 | req.url | user-provided value | +| execa.js:9:15:9:17 | cmd | execa.js:6:25:6:31 | req.url | execa.js:9:15:9:17 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:10:14:10:16 | cmd | execa.js:6:25:6:31 | req.url | execa.js:10:14:10:16 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:11:32:11:34 | cmd | execa.js:6:25:6:31 | req.url | execa.js:11:32:11:34 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:12:33:12:35 | cmd | execa.js:6:25:6:31 | req.url | execa.js:12:33:12:35 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:14:17:14:19 | cmd | execa.js:6:25:6:31 | req.url | execa.js:14:17:14:19 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:15:17:15:19 | cmd | execa.js:6:25:6:31 | req.url | execa.js:15:17:15:19 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:16:17:16:19 | cmd | execa.js:6:25:6:31 | req.url | execa.js:16:17:16:19 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:17:17:17:19 | cmd | execa.js:6:25:6:31 | req.url | execa.js:17:17:17:19 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:18:15:18:17 | cmd | execa.js:6:25:6:31 | req.url | execa.js:18:15:18:17 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:19:15:19:17 | cmd | execa.js:6:25:6:31 | req.url | execa.js:19:15:19:17 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:21:24:21:32 | cmd + arg | execa.js:6:25:6:31 | req.url | execa.js:21:24:21:32 | cmd + arg | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:21:24:21:32 | cmd + arg | execa.js:7:25:7:31 | req.url | execa.js:21:24:21:32 | cmd + arg | This command line depends on a $@. | execa.js:7:25:7:31 | req.url | user-provided value | +| execa.js:22:22:22:30 | cmd + arg | execa.js:6:25:6:31 | req.url | execa.js:22:22:22:30 | cmd + arg | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:22:22:22:30 | cmd + arg | execa.js:7:25:7:31 | req.url | execa.js:22:22:22:30 | cmd + arg | This command line depends on a $@. | execa.js:7:25:7:31 | req.url | user-provided value | +| execa.js:23:24:23:32 | cmd + arg | execa.js:6:25:6:31 | req.url | execa.js:23:24:23:32 | cmd + arg | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:23:24:23:32 | cmd + arg | execa.js:7:25:7:31 | req.url | execa.js:23:24:23:32 | cmd + arg | This command line depends on a $@. | execa.js:7:25:7:31 | req.url | user-provided value | +| execa.js:24:22:24:30 | cmd + arg | execa.js:6:25:6:31 | req.url | execa.js:24:22:24:30 | cmd + arg | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:24:22:24:30 | cmd + arg | execa.js:7:25:7:31 | req.url | execa.js:24:22:24:30 | cmd + arg | This command line depends on a $@. | execa.js:7:25:7:31 | req.url | user-provided value | | form-parsers.js:9:8:9:39 | "touch ... nalname | form-parsers.js:9:19:9:26 | req.file | form-parsers.js:9:8:9:39 | "touch ... nalname | This command line depends on a $@. | form-parsers.js:9:19:9:26 | req.file | user-provided value | | form-parsers.js:14:10:14:37 | "touch ... nalname | form-parsers.js:13:3:13:11 | req.files | form-parsers.js:14:10:14:37 | "touch ... nalname | This command line depends on a $@. | form-parsers.js:13:3:13:11 | req.files | user-provided value | | form-parsers.js:25:10:25:28 | "touch " + filename | form-parsers.js:24:48:24:55 | filename | form-parsers.js:25:10:25:28 | "touch " + filename | This command line depends on a $@. | form-parsers.js:24:48:24:55 | filename | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/execa.js b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/execa.js new file mode 100644 index 000000000000..936a6910de45 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/execa.js @@ -0,0 +1,25 @@ +import { execa, execaSync, execaCommand, execaCommandSync, $ } from 'execa'; +import http from 'node:http' +import url from 'url' + +http.createServer(async function (req, res) { + let cmd = url.parse(req.url, true).query["cmd"][0]; + let arg = url.parse(req.url, true).query["arg"]; + + await $`${cmd} ${arg}`; // NOT OK + $.sync`${cmd} ${arg}`; // NOT OK + await $({ shell: true })`${cmd} ${arg}` // NOT OK + await $({ shell: false })`${cmd} ${arg}` // NOT OK + + await execa(cmd, [arg]); // NOT OK + await execa(cmd, { shell: true }); // NOT OK + await execa(cmd, { shell: true }); // NOT OK + await execa(cmd, [arg], { shell: true }); // NOT OK + execaSync(cmd, [arg]); // NOT OK + execaSync(cmd, [arg], { shell: true }); // NOT OK + + await execaCommand(cmd + arg); // NOT OK + execaCommandSync(cmd + arg); // NOT OK + await execaCommand(cmd + arg, { shell: true }); // NOT OK + execaCommandSync(cmd + arg, { shell: true }); // NOT OK +}); \ No newline at end of file From 5bc21a6178e414680381e06b7916e57978a49914 Mon Sep 17 00:00:00 2001 From: amammad <77095239+amammad@users.noreply.github.com> Date: Fri, 6 Oct 2023 16:09:05 +0200 Subject: [PATCH 04/10] delete old tests --- .../frameworks/Execa/Execa.expected | 68 ------------------- .../library-tests/frameworks/Execa/tst.js | 53 --------------- 2 files changed, 121 deletions(-) delete mode 100644 javascript/ql/test/library-tests/frameworks/Execa/Execa.expected delete mode 100644 javascript/ql/test/library-tests/frameworks/Execa/tst.js diff --git a/javascript/ql/test/library-tests/frameworks/Execa/Execa.expected b/javascript/ql/test/library-tests/frameworks/Execa/Execa.expected deleted file mode 100644 index c4e12a8dca6e..000000000000 --- a/javascript/ql/test/library-tests/frameworks/Execa/Execa.expected +++ /dev/null @@ -1,68 +0,0 @@ -test_FileSystemAccess -| tst.js:22:9:22:23 | { shell: true } | -| tst.js:24:9:24:24 | { shell: false } | -| tst.js:28:13:28:22 | 'aCommand' | -| tst.js:28:25:28:36 | ['example1'] | -| tst.js:30:13:30:17 | 'git' | -| tst.js:30:20:30:31 | ['example1'] | -| tst.js:32:13:32:47 | 'echo e ... ple 11' | -| tst.js:32:50:32:64 | { shell: true } | -| tst.js:33:13:33:29 | 'echo example 10' | -| tst.js:33:32:33:52 | ['; ech ... le 11'] | -| tst.js:33:55:33:69 | { shell: true } | -| tst.js:36:11:36:16 | 'echo' | -| tst.js:36:19:36:35 | ['example5 sync'] | -| tst.js:38:20:38:41 | "git " ... gument" | -| tst.js:39:20:39:51 | `git ${ ... ndSync` | -| tst.js:41:18:41:20 | arg | -| tst.js:43:18:43:39 | "echo 1 ... echo 2" | -| tst.js:43:42:43:56 | { shell: true } | -| tst.js:49:9:49:27 | { inputFile: file } | -| tst.js:50:13:50:17 | 'cat' | -| tst.js:50:20:50:38 | { inputFile: file } | -| tst.js:51:13:51:18 | 'echo' | -| tst.js:51:21:51:32 | ['example2'] | -| tst.js:52:13:52:18 | 'echo' | -| tst.js:52:21:52:32 | ['example3'] | -| tst.js:53:13:53:18 | 'echo' | -| tst.js:53:21:53:32 | ['example4'] | -| tst.js:53:35:53:47 | { all: true } | -test_MissingFileSystemAccess -| tst.js:47:35:47:38 | file | -| tst.js:51:46:51:49 | file | -| tst.js:52:46:52:49 | file | -| tst.js:53:58:53:61 | file | -test_SystemCommandExecution -| tst.js:1:71:1:71 | $ | -| tst.js:7:7:7:7 | $ | -| tst.js:9:7:9:7 | $ | -| tst.js:10:1:10:1 | $ | -| tst.js:10:1:10:6 | $.sync | -| tst.js:14:7:14:7 | $ | -| tst.js:16:7:16:7 | $ | -| tst.js:17:1:17:1 | $ | -| tst.js:17:1:17:6 | $.sync | -| tst.js:19:1:19:1 | $ | -| tst.js:19:1:19:6 | $.sync | -| tst.js:20:7:20:7 | $ | -| tst.js:22:7:22:7 | $ | -| tst.js:22:7:22:24 | $({ shell: true }) | -| tst.js:24:7:24:7 | $ | -| tst.js:24:7:24:25 | $({ shell: false }) | -| tst.js:28:7:28:37 | execa(' ... ple1']) | -| tst.js:30:7:30:32 | execa(' ... ple1']) | -| tst.js:32:7:32:65 | execa(' ... true }) | -| tst.js:33:7:33:70 | execa(' ... true }) | -| tst.js:36:1:36:36 | execaSy ... sync']) | -| tst.js:38:7:38:42 | execaCo ... ument") | -| tst.js:39:7:39:52 | execaCo ... dSync`) | -| tst.js:41:1:41:21 | execaCo ... nc(arg) | -| tst.js:43:1:43:57 | execaCo ... true }) | -| tst.js:47:7:47:7 | $ | -| tst.js:49:7:49:7 | $ | -| tst.js:49:7:49:28 | $({ inp ... file }) | -| tst.js:50:7:50:39 | execa(' ... file }) | -| tst.js:51:7:51:33 | execa(' ... ple2']) | -| tst.js:52:7:52:33 | execa(' ... ple3']) | -| tst.js:53:7:53:48 | execa(' ... true }) | -test_FileNameSource diff --git a/javascript/ql/test/library-tests/frameworks/Execa/tst.js b/javascript/ql/test/library-tests/frameworks/Execa/tst.js deleted file mode 100644 index e31fa07dbb43..000000000000 --- a/javascript/ql/test/library-tests/frameworks/Execa/tst.js +++ /dev/null @@ -1,53 +0,0 @@ -import { execa, execaSync, execaCommand, execaCommandSync, execaNode, $ } from 'execa'; - -const arg = process.argv[0]; - -// Node.js scripts -// GOOD -await $`echo example1`.pipeStderr(`tmp`); -// BAD argument injection -await $`ssh ${"example2"}`.pipeStderr(`tmp`); -$.sync`echo example2 sync` -// Multiple arguments -const args = ["arg:" + arg, 'example3', '&', 'rainbows!']; -// GOOD -await $`${arg} sth`; -// GOOD only one command can be executed -await $`${arg}`; -$.sync`${arg}` -// BAD argument injection -$.sync`git ${args} ${args}` -await $`git ${["-o", "-lps"]}` -// if shell: true then all inputs except first are dangerous -await $({ shell: true })`echo example6 ${";echo example6 > tmpdir/example6"}` -// GOOD -await $({ shell: false })`echo example6 ${";echo example6 > tmpdir/example6"}` - -// execa -// GOOD -await execa('aCommand', ['example1']); -// BAD argument injection -await execa('git', ['example1']); -// BAD shell is enable -await execa('echo example 10 ; echo example 11', { shell: true }); -await execa('echo example 10', ['; echo example 11'], { shell: true }); - -// BAD argument injection -execaSync('echo', ['example5 sync']); -// BAD argument injection -await execaCommand("git " + "badArgument"); -await execaCommand(`git ${"arg1"} execaCommandSync`); -// bad totally controllable argument -execaCommandSync(arg); -// BAD shell is enable -execaCommandSync("echo 1 " + "; echo 2", { shell: true }); - -// FileSystemAccess -// Piping stdout to a file -await $`echo example8`.pipeStdout(file) -// Piping stdin from a file -await $({ inputFile: file })`cat` -await execa('cat', { inputFile: file }); -await execa('echo', ['example2']).pipeStdout(file); -await execa('echo', ['example3']).pipeStderr(file); -await execa('echo', ['example4'], { all: true }).pipeAll(file); From de2ee4d2899b7c5003bb0ea333f1b6b71c2da222 Mon Sep 17 00:00:00 2001 From: amammad <77095239+amammad@users.noreply.github.com> Date: Wed, 11 Oct 2023 14:36:56 +0200 Subject: [PATCH 05/10] stash I can't especify the argument and command differences with new API --- .../semmle/javascript/frameworks/Execa.qll | 82 ++++++------------- 1 file changed, 25 insertions(+), 57 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll b/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll index 5cfecc1c814d..a851f6099cea 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll @@ -97,65 +97,50 @@ module Execa { } /** - * A call to `execa.$` or `execa.$.sync` tag functions + * A call to `execa.$` or `execa.$.sync` or `execa.$({})` or `execa.$.sync({})` tag functions */ - private class ExecaScriptExpr extends DataFlow::ExprNode { + private class ExecaScriptCall extends API::CallNode { boolean isSync; - ExecaScriptExpr() { - this.asExpr() = - [ - API::moduleImport("execa").getMember("$"), - API::moduleImport("execa").getMember("$").getReturn() - ].getAValueReachableFromSource().asExpr() and - isSync = false - or - this.asExpr() = - [ - API::moduleImport("execa").getMember("$").getMember("sync"), - API::moduleImport("execa").getMember("$").getMember("sync").getReturn() - ].getAValueReachableFromSource().asExpr() and - isSync = true + ExecaScriptCall() { + exists(API::Node script | + script = + [ + API::moduleImport("execa").getMember("$"), + API::moduleImport("execa").getMember("$").getReturn() + ] + | + this = script.getACall() and + isSync = false + or + this = script.getMember("sync").getACall() and + isSync = true + ) } } + API::Node test() { result = API::moduleImport("execa").getMember("$").getASuccessor*() } + /** * The system command execution nodes for `execa.$` or `execa.$.sync` tag functions */ - class ExecaScriptEec extends SystemCommandExecution, ExecaScriptExpr { - ExecaScriptEec() { isSync = [false, true] } + class ExecaScript extends SystemCommandExecution, ExecaScriptCall { + ExecaScript() { isSync = [false, true] } - override DataFlow::Node getACommandArgument() { - exists(TemplateLiteral tl | isFirstTaggedTemplateParameter(this.asExpr(), tl) | - result.asExpr() = tl.getChildExpr(0) and - not result.asExpr().mayHaveStringValue(" ") // exclude whitespace - ) - } + override DataFlow::Node getACommandArgument() { result = this.getParameter(1).asSink() } override predicate isShellInterpreted(DataFlow::Node arg) { - // $({shell: true})`${cmd} ${arg0} ... ${arg1}` - // ISSUE: $`cmd args` I can't reach the tag function argument easily - exists(TemplateLiteral tmpL | isFirstTaggedTemplateParameter(this.asExpr(), tmpL) | - arg.asExpr() = tmpL.getAChildExpr() and - isExecaShellEnableWithExpr(this.asExpr().(CallExpr).getArgument(0)) and - not arg.asExpr().mayHaveStringValue(" ") // exclude whitespace - ) + isExecaShellEnable(this.getParameter(0)) and + arg = this.getParameter(0).asSink() } override DataFlow::Node getArgumentList() { - // $`${cmd} ${arg0} ... ${argn}` - exists(TemplateLiteral tmpL | isFirstTaggedTemplateParameter(this.asExpr(), tmpL) | - result.asExpr() = tmpL.getAChildExpr() and - not result.asExpr() = tmpL.getChildExpr(0) and - not result.asExpr().mayHaveStringValue(" ") // exclude whitespace - ) + result = this.getParameter(any(int i | i > 1)).asSink() } override predicate isSync() { isSync = true } - override DataFlow::Node getOptionsArg() { - result = this.asExpr().getAChildExpr().flow() and result.asExpr() instanceof ObjectExpr - } + override DataFlow::Node getOptionsArg() { result = this.getParameter(0).asSink() } } /** @@ -207,14 +192,6 @@ module Execa { } } - // Holds if left parameter is the left child of a template literal and returns the template literal - private predicate isFirstTaggedTemplateParameter(Expr left, TemplateLiteral templateLiteral) { - exists(TaggedTemplateExpr parent | - templateLiteral = parent.getTemplate() and - left = parent.getChildExpr(0) - ) - } - /** * Holds whether Execa has shell enabled options or not, get Parameter responsible for options */ @@ -222,13 +199,4 @@ module Execa { private predicate isExecaShellEnable(API::Node n) { n.getMember("shell").asSink().asExpr().(BooleanLiteral).getValue() = "true" } - - // Holds whether Execa has shell enabled options or not, get Parameter responsible for options - private predicate isExecaShellEnableWithExpr(Expr n) { - exists(ObjectExpr o, Property p | o = n.getAChildExpr*() | - o.getAChild() = p and - p.getAChild().(Label).getName() = "shell" and - p.getAChild().(Literal).getValue() = "true" - ) - } } From b24c6fd57946ee3a14ffca59f2799819469934cc Mon Sep 17 00:00:00 2001 From: amammad <77095239+amammad@users.noreply.github.com> Date: Wed, 11 Oct 2023 17:34:33 +0200 Subject: [PATCH 06/10] for demonstration --- .../semmle/javascript/frameworks/Execa.qll | 11 +++--- .../CWE-078/CommandInjection/execa.js | 36 ++++++++++++------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll b/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll index a851f6099cea..db504b06c600 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll @@ -119,8 +119,6 @@ module Execa { } } - API::Node test() { result = API::moduleImport("execa").getMember("$").getASuccessor*() } - /** * The system command execution nodes for `execa.$` or `execa.$.sync` tag functions */ @@ -131,16 +129,17 @@ module Execa { override predicate isShellInterpreted(DataFlow::Node arg) { isExecaShellEnable(this.getParameter(0)) and - arg = this.getParameter(0).asSink() + arg = this.getAParameter().asSink() } override DataFlow::Node getArgumentList() { - result = this.getParameter(any(int i | i > 1)).asSink() + result = this.getParameter(any(int i | i > 1)).asSink() and + not exists(string s | this.getACall().getArgument(0).mayHaveStringValue(s) | s.matches("")) } - override predicate isSync() { isSync = true } - override DataFlow::Node getOptionsArg() { result = this.getParameter(0).asSink() } + + override predicate isSync() { isSync = true } } /** diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/execa.js b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/execa.js index 936a6910de45..5155b2285505 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/execa.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/execa.js @@ -4,22 +4,32 @@ import url from 'url' http.createServer(async function (req, res) { let cmd = url.parse(req.url, true).query["cmd"][0]; - let arg = url.parse(req.url, true).query["arg"]; + let arg1 = url.parse(req.url, true).query["arg1"]; + let arg2 = url.parse(req.url, true).query["arg2"]; - await $`${cmd} ${arg}`; // NOT OK - $.sync`${cmd} ${arg}`; // NOT OK - await $({ shell: true })`${cmd} ${arg}` // NOT OK - await $({ shell: false })`${cmd} ${arg}` // NOT OK + await $`${cmd} ${arg1} ${arg2}`; // NOT OK + await $`ssh ${arg1} ${arg2}`; // NOT OK + $({ shell: false }).sync`${cmd} ${arg} ${arg} ${arg2}`; // NOT OK + $({ shell: true }).sync`${cmd} ${arg} ${arg} ${arg2}`; // NOT OK + $({ shell: false }).sync`ssh ${arg} ${arg} ${arg2}`; // NOT OK - await execa(cmd, [arg]); // NOT OK + $.sync`${cmd} ${arg1} ${arg2}`; // NOT OK + $.sync`ssh ${arg1} ${arg2}`; // NOT OK + await $({ shell: true })`${cmd} ${arg1} ${arg2}` // NOT OK + await $({ shell: false })`${cmd} ${arg1} ${arg2}` // NOT OK + await $({ shell: false })`ssh ${arg1} ${arg2}` // NOT OK + + await execa(cmd, [arg1]); // NOT OK await execa(cmd, { shell: true }); // NOT OK await execa(cmd, { shell: true }); // NOT OK - await execa(cmd, [arg], { shell: true }); // NOT OK - execaSync(cmd, [arg]); // NOT OK - execaSync(cmd, [arg], { shell: true }); // NOT OK + await execa(cmd, [arg1], { shell: true }); // NOT OK + + execaSync(cmd, [arg1]); // NOT OK + execaSync(cmd, [arg1], { shell: true }); // NOT OK + + await execaCommand(cmd + arg1); // NOT OK + await execaCommand(cmd + arg1, { shell: true }); // NOT OK - await execaCommand(cmd + arg); // NOT OK - execaCommandSync(cmd + arg); // NOT OK - await execaCommand(cmd + arg, { shell: true }); // NOT OK - execaCommandSync(cmd + arg, { shell: true }); // NOT OK + execaCommandSync(cmd + arg1); // NOT OK + execaCommandSync(cmd + arg1, { shell: true }); // NOT OK }); \ No newline at end of file From 261cabde67fdbb2f36077c0c97607a668e74d380 Mon Sep 17 00:00:00 2001 From: amammad <77095239+amammad@users.noreply.github.com> Date: Wed, 11 Oct 2023 17:44:12 +0200 Subject: [PATCH 07/10] better comments --- javascript/ql/lib/semmle/javascript/frameworks/Execa.qll | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll b/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll index db504b06c600..90c84107120a 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll @@ -133,7 +133,12 @@ module Execa { } override DataFlow::Node getArgumentList() { + result = this.getParameter(any(int i | i > 2)).asSink() and + // here I should check if the first parameter of Template literal is the rightmost string of this Template literal then the arguments of this command execution will be the second and third and .. parameters + not exists(string s | this.getACall().getArgument(0).mayHaveStringValue(s) | s.matches("")) + or result = this.getParameter(any(int i | i > 1)).asSink() and + // here I should check if the first parameter of Template literal is a constant which is the command, then the arguments of this command execution will be the first, second and third and .. parameters not exists(string s | this.getACall().getArgument(0).mayHaveStringValue(s) | s.matches("")) } From 3899f2cdf3c97c00dc7af67586ad38f34c7f9312 Mon Sep 17 00:00:00 2001 From: amammad <77095239+amammad@users.noreply.github.com> Date: Thu, 12 Oct 2023 10:44:30 +0200 Subject: [PATCH 08/10] upgrade execa scripts --- .../semmle/javascript/frameworks/Execa.qll | 20 +- .../CommandInjection.expected | 290 +++++++++++------- .../CWE-078/CommandInjection/execa.js | 37 +-- 3 files changed, 213 insertions(+), 134 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll b/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll index 90c84107120a..c73b69199578 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll @@ -125,7 +125,10 @@ module Execa { class ExecaScript extends SystemCommandExecution, ExecaScriptCall { ExecaScript() { isSync = [false, true] } - override DataFlow::Node getACommandArgument() { result = this.getParameter(1).asSink() } + override DataFlow::Node getACommandArgument() { + result = this.getParameter(1).asSink() and + not isTaggedTemplateFirstChildAnElement(this.getParameter(1).asSink().asExpr().getParent()) + } override predicate isShellInterpreted(DataFlow::Node arg) { isExecaShellEnable(this.getParameter(0)) and @@ -133,13 +136,11 @@ module Execa { } override DataFlow::Node getArgumentList() { - result = this.getParameter(any(int i | i > 2)).asSink() and - // here I should check if the first parameter of Template literal is the rightmost string of this Template literal then the arguments of this command execution will be the second and third and .. parameters - not exists(string s | this.getACall().getArgument(0).mayHaveStringValue(s) | s.matches("")) + result = this.getParameter(any(int i | i >= 1)).asSink() and + isTaggedTemplateFirstChildAnElement(this.getParameter(1).asSink().asExpr().getParent()) or - result = this.getParameter(any(int i | i > 1)).asSink() and - // here I should check if the first parameter of Template literal is a constant which is the command, then the arguments of this command execution will be the first, second and third and .. parameters - not exists(string s | this.getACall().getArgument(0).mayHaveStringValue(s) | s.matches("")) + result = this.getParameter(any(int i | i >= 2)).asSink() and + not isTaggedTemplateFirstChildAnElement(this.getParameter(1).asSink().asExpr().getParent()) } override DataFlow::Node getOptionsArg() { result = this.getParameter(0).asSink() } @@ -196,6 +197,11 @@ module Execa { } } + /** Gets a TemplateLiteral and check if first child is a template element */ + private predicate isTaggedTemplateFirstChildAnElement(TemplateLiteral templateLit) { + exists(templateLit.getChildExpr(0).(TemplateElement)) + } + /** * Holds whether Execa has shell enabled options or not, get Parameter responsible for options */ diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/CommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/CommandInjection.expected index 02f1ccf774de..20fa7f652796 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/CommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/CommandInjection.expected @@ -110,48 +110,72 @@ nodes | execa.js:6:15:6:54 | url.par ... md"][0] | | execa.js:6:25:6:31 | req.url | | execa.js:6:25:6:31 | req.url | -| execa.js:7:9:7:51 | arg | -| execa.js:7:15:7:38 | url.par ... , true) | -| execa.js:7:15:7:44 | url.par ... ).query | -| execa.js:7:15:7:51 | url.par ... ["arg"] | -| execa.js:7:25:7:31 | req.url | -| execa.js:7:25:7:31 | req.url | -| execa.js:9:15:9:17 | cmd | -| execa.js:9:15:9:17 | cmd | -| execa.js:10:14:10:16 | cmd | -| execa.js:10:14:10:16 | cmd | -| execa.js:11:32:11:34 | cmd | -| execa.js:11:32:11:34 | cmd | -| execa.js:12:33:12:35 | cmd | -| execa.js:12:33:12:35 | cmd | -| execa.js:14:17:14:19 | cmd | -| execa.js:14:17:14:19 | cmd | -| execa.js:15:17:15:19 | cmd | -| execa.js:15:17:15:19 | cmd | -| execa.js:16:17:16:19 | cmd | -| execa.js:16:17:16:19 | cmd | -| execa.js:17:17:17:19 | cmd | -| execa.js:17:17:17:19 | cmd | -| execa.js:18:15:18:17 | cmd | -| execa.js:18:15:18:17 | cmd | -| execa.js:19:15:19:17 | cmd | -| execa.js:19:15:19:17 | cmd | -| execa.js:21:24:21:26 | cmd | -| execa.js:21:24:21:32 | cmd + arg | -| execa.js:21:24:21:32 | cmd + arg | -| execa.js:21:30:21:32 | arg | -| execa.js:22:22:22:24 | cmd | -| execa.js:22:22:22:30 | cmd + arg | -| execa.js:22:22:22:30 | cmd + arg | -| execa.js:22:28:22:30 | arg | -| execa.js:23:24:23:26 | cmd | -| execa.js:23:24:23:32 | cmd + arg | -| execa.js:23:24:23:32 | cmd + arg | -| execa.js:23:30:23:32 | arg | -| execa.js:24:22:24:24 | cmd | -| execa.js:24:22:24:30 | cmd + arg | -| execa.js:24:22:24:30 | cmd + arg | -| execa.js:24:28:24:30 | arg | +| execa.js:7:9:7:53 | arg1 | +| execa.js:7:16:7:39 | url.par ... , true) | +| execa.js:7:16:7:45 | url.par ... ).query | +| execa.js:7:16:7:53 | url.par ... "arg1"] | +| execa.js:7:26:7:32 | req.url | +| execa.js:7:26:7:32 | req.url | +| execa.js:8:9:8:53 | arg2 | +| execa.js:8:16:8:39 | url.par ... , true) | +| execa.js:8:16:8:45 | url.par ... ).query | +| execa.js:8:16:8:53 | url.par ... "arg2"] | +| execa.js:8:26:8:32 | req.url | +| execa.js:8:26:8:32 | req.url | +| execa.js:9:9:9:53 | arg3 | +| execa.js:9:16:9:39 | url.par ... , true) | +| execa.js:9:16:9:45 | url.par ... ).query | +| execa.js:9:16:9:53 | url.par ... "arg3"] | +| execa.js:9:26:9:32 | req.url | +| execa.js:9:26:9:32 | req.url | +| execa.js:11:15:11:17 | cmd | +| execa.js:11:15:11:17 | cmd | +| execa.js:13:32:13:34 | cmd | +| execa.js:13:32:13:34 | cmd | +| execa.js:14:31:14:33 | cmd | +| execa.js:14:31:14:33 | cmd | +| execa.js:17:14:17:16 | cmd | +| execa.js:17:14:17:16 | cmd | +| execa.js:19:32:19:34 | cmd | +| execa.js:19:32:19:34 | cmd | +| execa.js:20:33:20:35 | cmd | +| execa.js:20:33:20:35 | cmd | +| execa.js:23:17:23:19 | cmd | +| execa.js:23:17:23:19 | cmd | +| execa.js:24:17:24:19 | cmd | +| execa.js:24:17:24:19 | cmd | +| execa.js:25:17:25:19 | cmd | +| execa.js:25:17:25:19 | cmd | +| execa.js:26:17:26:19 | cmd | +| execa.js:26:17:26:19 | cmd | +| execa.js:28:15:28:17 | cmd | +| execa.js:28:15:28:17 | cmd | +| execa.js:29:15:29:17 | cmd | +| execa.js:29:15:29:17 | cmd | +| execa.js:31:24:31:26 | cmd | +| execa.js:31:24:31:47 | cmd + a ... + arg3 | +| execa.js:31:24:31:47 | cmd + a ... + arg3 | +| execa.js:31:30:31:33 | arg1 | +| execa.js:31:37:31:40 | arg2 | +| execa.js:31:44:31:47 | arg3 | +| execa.js:32:24:32:26 | cmd | +| execa.js:32:24:32:47 | cmd + a ... + arg3 | +| execa.js:32:24:32:47 | cmd + a ... + arg3 | +| execa.js:32:30:32:33 | arg1 | +| execa.js:32:37:32:40 | arg2 | +| execa.js:32:44:32:47 | arg3 | +| execa.js:34:22:34:24 | cmd | +| execa.js:34:22:34:45 | cmd + a ... + arg3 | +| execa.js:34:22:34:45 | cmd + a ... + arg3 | +| execa.js:34:28:34:31 | arg1 | +| execa.js:34:35:34:38 | arg2 | +| execa.js:34:42:34:45 | arg3 | +| execa.js:35:22:35:24 | cmd | +| execa.js:35:22:35:45 | cmd + a ... + arg3 | +| execa.js:35:22:35:45 | cmd + a ... + arg3 | +| execa.js:35:28:35:31 | arg1 | +| execa.js:35:35:35:38 | arg2 | +| execa.js:35:42:35:45 | arg3 | | form-parsers.js:9:8:9:39 | "touch ... nalname | | form-parsers.js:9:8:9:39 | "touch ... nalname | | form-parsers.js:9:19:9:26 | req.file | @@ -335,61 +359,99 @@ edges | execSeries.js:18:34:18:40 | req.url | execSeries.js:18:13:18:47 | require ... , true) | | execSeries.js:19:12:19:16 | [cmd] | execSeries.js:13:19:13:26 | commands | | execSeries.js:19:13:19:15 | cmd | execSeries.js:19:12:19:16 | [cmd] | -| execa.js:6:9:6:54 | cmd | execa.js:9:15:9:17 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:9:15:9:17 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:10:14:10:16 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:10:14:10:16 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:11:32:11:34 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:11:32:11:34 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:12:33:12:35 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:12:33:12:35 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:14:17:14:19 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:14:17:14:19 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:15:17:15:19 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:15:17:15:19 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:16:17:16:19 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:16:17:16:19 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:17:17:17:19 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:17:17:17:19 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:18:15:18:17 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:18:15:18:17 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:19:15:19:17 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:19:15:19:17 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:21:24:21:26 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:22:22:22:24 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:23:24:23:26 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:24:22:24:24 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:11:15:11:17 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:11:15:11:17 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:13:32:13:34 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:13:32:13:34 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:14:31:14:33 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:14:31:14:33 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:17:14:17:16 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:17:14:17:16 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:19:32:19:34 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:19:32:19:34 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:20:33:20:35 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:20:33:20:35 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:23:17:23:19 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:23:17:23:19 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:24:17:24:19 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:24:17:24:19 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:25:17:25:19 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:25:17:25:19 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:26:17:26:19 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:26:17:26:19 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:28:15:28:17 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:28:15:28:17 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:29:15:29:17 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:29:15:29:17 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:31:24:31:26 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:32:24:32:26 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:34:22:34:24 | cmd | +| execa.js:6:9:6:54 | cmd | execa.js:35:22:35:24 | cmd | | execa.js:6:15:6:38 | url.par ... , true) | execa.js:6:15:6:44 | url.par ... ).query | | execa.js:6:15:6:44 | url.par ... ).query | execa.js:6:15:6:51 | url.par ... ["cmd"] | | execa.js:6:15:6:51 | url.par ... ["cmd"] | execa.js:6:15:6:54 | url.par ... md"][0] | | execa.js:6:15:6:54 | url.par ... md"][0] | execa.js:6:9:6:54 | cmd | | execa.js:6:25:6:31 | req.url | execa.js:6:15:6:38 | url.par ... , true) | | execa.js:6:25:6:31 | req.url | execa.js:6:15:6:38 | url.par ... , true) | -| execa.js:7:9:7:51 | arg | execa.js:21:30:21:32 | arg | -| execa.js:7:9:7:51 | arg | execa.js:22:28:22:30 | arg | -| execa.js:7:9:7:51 | arg | execa.js:23:30:23:32 | arg | -| execa.js:7:9:7:51 | arg | execa.js:24:28:24:30 | arg | -| execa.js:7:15:7:38 | url.par ... , true) | execa.js:7:15:7:44 | url.par ... ).query | -| execa.js:7:15:7:44 | url.par ... ).query | execa.js:7:15:7:51 | url.par ... ["arg"] | -| execa.js:7:15:7:51 | url.par ... ["arg"] | execa.js:7:9:7:51 | arg | -| execa.js:7:25:7:31 | req.url | execa.js:7:15:7:38 | url.par ... , true) | -| execa.js:7:25:7:31 | req.url | execa.js:7:15:7:38 | url.par ... , true) | -| execa.js:21:24:21:26 | cmd | execa.js:21:24:21:32 | cmd + arg | -| execa.js:21:24:21:26 | cmd | execa.js:21:24:21:32 | cmd + arg | -| execa.js:21:30:21:32 | arg | execa.js:21:24:21:32 | cmd + arg | -| execa.js:21:30:21:32 | arg | execa.js:21:24:21:32 | cmd + arg | -| execa.js:22:22:22:24 | cmd | execa.js:22:22:22:30 | cmd + arg | -| execa.js:22:22:22:24 | cmd | execa.js:22:22:22:30 | cmd + arg | -| execa.js:22:28:22:30 | arg | execa.js:22:22:22:30 | cmd + arg | -| execa.js:22:28:22:30 | arg | execa.js:22:22:22:30 | cmd + arg | -| execa.js:23:24:23:26 | cmd | execa.js:23:24:23:32 | cmd + arg | -| execa.js:23:24:23:26 | cmd | execa.js:23:24:23:32 | cmd + arg | -| execa.js:23:30:23:32 | arg | execa.js:23:24:23:32 | cmd + arg | -| execa.js:23:30:23:32 | arg | execa.js:23:24:23:32 | cmd + arg | -| execa.js:24:22:24:24 | cmd | execa.js:24:22:24:30 | cmd + arg | -| execa.js:24:22:24:24 | cmd | execa.js:24:22:24:30 | cmd + arg | -| execa.js:24:28:24:30 | arg | execa.js:24:22:24:30 | cmd + arg | -| execa.js:24:28:24:30 | arg | execa.js:24:22:24:30 | cmd + arg | +| execa.js:7:9:7:53 | arg1 | execa.js:31:30:31:33 | arg1 | +| execa.js:7:9:7:53 | arg1 | execa.js:32:30:32:33 | arg1 | +| execa.js:7:9:7:53 | arg1 | execa.js:34:28:34:31 | arg1 | +| execa.js:7:9:7:53 | arg1 | execa.js:35:28:35:31 | arg1 | +| execa.js:7:16:7:39 | url.par ... , true) | execa.js:7:16:7:45 | url.par ... ).query | +| execa.js:7:16:7:45 | url.par ... ).query | execa.js:7:16:7:53 | url.par ... "arg1"] | +| execa.js:7:16:7:53 | url.par ... "arg1"] | execa.js:7:9:7:53 | arg1 | +| execa.js:7:26:7:32 | req.url | execa.js:7:16:7:39 | url.par ... , true) | +| execa.js:7:26:7:32 | req.url | execa.js:7:16:7:39 | url.par ... , true) | +| execa.js:8:9:8:53 | arg2 | execa.js:31:37:31:40 | arg2 | +| execa.js:8:9:8:53 | arg2 | execa.js:32:37:32:40 | arg2 | +| execa.js:8:9:8:53 | arg2 | execa.js:34:35:34:38 | arg2 | +| execa.js:8:9:8:53 | arg2 | execa.js:35:35:35:38 | arg2 | +| execa.js:8:16:8:39 | url.par ... , true) | execa.js:8:16:8:45 | url.par ... ).query | +| execa.js:8:16:8:45 | url.par ... ).query | execa.js:8:16:8:53 | url.par ... "arg2"] | +| execa.js:8:16:8:53 | url.par ... "arg2"] | execa.js:8:9:8:53 | arg2 | +| execa.js:8:26:8:32 | req.url | execa.js:8:16:8:39 | url.par ... , true) | +| execa.js:8:26:8:32 | req.url | execa.js:8:16:8:39 | url.par ... , true) | +| execa.js:9:9:9:53 | arg3 | execa.js:31:44:31:47 | arg3 | +| execa.js:9:9:9:53 | arg3 | execa.js:32:44:32:47 | arg3 | +| execa.js:9:9:9:53 | arg3 | execa.js:34:42:34:45 | arg3 | +| execa.js:9:9:9:53 | arg3 | execa.js:35:42:35:45 | arg3 | +| execa.js:9:16:9:39 | url.par ... , true) | execa.js:9:16:9:45 | url.par ... ).query | +| execa.js:9:16:9:45 | url.par ... ).query | execa.js:9:16:9:53 | url.par ... "arg3"] | +| execa.js:9:16:9:53 | url.par ... "arg3"] | execa.js:9:9:9:53 | arg3 | +| execa.js:9:26:9:32 | req.url | execa.js:9:16:9:39 | url.par ... , true) | +| execa.js:9:26:9:32 | req.url | execa.js:9:16:9:39 | url.par ... , true) | +| execa.js:31:24:31:26 | cmd | execa.js:31:24:31:47 | cmd + a ... + arg3 | +| execa.js:31:24:31:26 | cmd | execa.js:31:24:31:47 | cmd + a ... + arg3 | +| execa.js:31:30:31:33 | arg1 | execa.js:31:24:31:47 | cmd + a ... + arg3 | +| execa.js:31:30:31:33 | arg1 | execa.js:31:24:31:47 | cmd + a ... + arg3 | +| execa.js:31:37:31:40 | arg2 | execa.js:31:24:31:47 | cmd + a ... + arg3 | +| execa.js:31:37:31:40 | arg2 | execa.js:31:24:31:47 | cmd + a ... + arg3 | +| execa.js:31:44:31:47 | arg3 | execa.js:31:24:31:47 | cmd + a ... + arg3 | +| execa.js:31:44:31:47 | arg3 | execa.js:31:24:31:47 | cmd + a ... + arg3 | +| execa.js:32:24:32:26 | cmd | execa.js:32:24:32:47 | cmd + a ... + arg3 | +| execa.js:32:24:32:26 | cmd | execa.js:32:24:32:47 | cmd + a ... + arg3 | +| execa.js:32:30:32:33 | arg1 | execa.js:32:24:32:47 | cmd + a ... + arg3 | +| execa.js:32:30:32:33 | arg1 | execa.js:32:24:32:47 | cmd + a ... + arg3 | +| execa.js:32:37:32:40 | arg2 | execa.js:32:24:32:47 | cmd + a ... + arg3 | +| execa.js:32:37:32:40 | arg2 | execa.js:32:24:32:47 | cmd + a ... + arg3 | +| execa.js:32:44:32:47 | arg3 | execa.js:32:24:32:47 | cmd + a ... + arg3 | +| execa.js:32:44:32:47 | arg3 | execa.js:32:24:32:47 | cmd + a ... + arg3 | +| execa.js:34:22:34:24 | cmd | execa.js:34:22:34:45 | cmd + a ... + arg3 | +| execa.js:34:22:34:24 | cmd | execa.js:34:22:34:45 | cmd + a ... + arg3 | +| execa.js:34:28:34:31 | arg1 | execa.js:34:22:34:45 | cmd + a ... + arg3 | +| execa.js:34:28:34:31 | arg1 | execa.js:34:22:34:45 | cmd + a ... + arg3 | +| execa.js:34:35:34:38 | arg2 | execa.js:34:22:34:45 | cmd + a ... + arg3 | +| execa.js:34:35:34:38 | arg2 | execa.js:34:22:34:45 | cmd + a ... + arg3 | +| execa.js:34:42:34:45 | arg3 | execa.js:34:22:34:45 | cmd + a ... + arg3 | +| execa.js:34:42:34:45 | arg3 | execa.js:34:22:34:45 | cmd + a ... + arg3 | +| execa.js:35:22:35:24 | cmd | execa.js:35:22:35:45 | cmd + a ... + arg3 | +| execa.js:35:22:35:24 | cmd | execa.js:35:22:35:45 | cmd + a ... + arg3 | +| execa.js:35:28:35:31 | arg1 | execa.js:35:22:35:45 | cmd + a ... + arg3 | +| execa.js:35:28:35:31 | arg1 | execa.js:35:22:35:45 | cmd + a ... + arg3 | +| execa.js:35:35:35:38 | arg2 | execa.js:35:22:35:45 | cmd + a ... + arg3 | +| execa.js:35:35:35:38 | arg2 | execa.js:35:22:35:45 | cmd + a ... + arg3 | +| execa.js:35:42:35:45 | arg3 | execa.js:35:22:35:45 | cmd + a ... + arg3 | +| execa.js:35:42:35:45 | arg3 | execa.js:35:22:35:45 | cmd + a ... + arg3 | | form-parsers.js:9:19:9:26 | req.file | form-parsers.js:9:19:9:39 | req.fil ... nalname | | form-parsers.js:9:19:9:26 | req.file | form-parsers.js:9:19:9:39 | req.fil ... nalname | | form-parsers.js:9:19:9:39 | req.fil ... nalname | form-parsers.js:9:8:9:39 | "touch ... nalname | @@ -495,24 +557,34 @@ edges | exec-sh2.js:10:12:10:57 | cp.spaw ... ptions) | exec-sh2.js:14:25:14:31 | req.url | exec-sh2.js:10:40:10:46 | command | This command line depends on a $@. | exec-sh2.js:14:25:14:31 | req.url | user-provided value | | exec-sh.js:15:12:15:61 | cp.spaw ... ptions) | exec-sh.js:19:25:19:31 | req.url | exec-sh.js:15:44:15:50 | command | This command line depends on a $@. | exec-sh.js:19:25:19:31 | req.url | user-provided value | | execSeries.js:14:41:14:47 | command | execSeries.js:18:34:18:40 | req.url | execSeries.js:14:41:14:47 | command | This command line depends on a $@. | execSeries.js:18:34:18:40 | req.url | user-provided value | -| execa.js:9:15:9:17 | cmd | execa.js:6:25:6:31 | req.url | execa.js:9:15:9:17 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:10:14:10:16 | cmd | execa.js:6:25:6:31 | req.url | execa.js:10:14:10:16 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:11:32:11:34 | cmd | execa.js:6:25:6:31 | req.url | execa.js:11:32:11:34 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:12:33:12:35 | cmd | execa.js:6:25:6:31 | req.url | execa.js:12:33:12:35 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:14:17:14:19 | cmd | execa.js:6:25:6:31 | req.url | execa.js:14:17:14:19 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:15:17:15:19 | cmd | execa.js:6:25:6:31 | req.url | execa.js:15:17:15:19 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:16:17:16:19 | cmd | execa.js:6:25:6:31 | req.url | execa.js:16:17:16:19 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:17:17:17:19 | cmd | execa.js:6:25:6:31 | req.url | execa.js:17:17:17:19 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:18:15:18:17 | cmd | execa.js:6:25:6:31 | req.url | execa.js:18:15:18:17 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:19:15:19:17 | cmd | execa.js:6:25:6:31 | req.url | execa.js:19:15:19:17 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:21:24:21:32 | cmd + arg | execa.js:6:25:6:31 | req.url | execa.js:21:24:21:32 | cmd + arg | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:21:24:21:32 | cmd + arg | execa.js:7:25:7:31 | req.url | execa.js:21:24:21:32 | cmd + arg | This command line depends on a $@. | execa.js:7:25:7:31 | req.url | user-provided value | -| execa.js:22:22:22:30 | cmd + arg | execa.js:6:25:6:31 | req.url | execa.js:22:22:22:30 | cmd + arg | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:22:22:22:30 | cmd + arg | execa.js:7:25:7:31 | req.url | execa.js:22:22:22:30 | cmd + arg | This command line depends on a $@. | execa.js:7:25:7:31 | req.url | user-provided value | -| execa.js:23:24:23:32 | cmd + arg | execa.js:6:25:6:31 | req.url | execa.js:23:24:23:32 | cmd + arg | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:23:24:23:32 | cmd + arg | execa.js:7:25:7:31 | req.url | execa.js:23:24:23:32 | cmd + arg | This command line depends on a $@. | execa.js:7:25:7:31 | req.url | user-provided value | -| execa.js:24:22:24:30 | cmd + arg | execa.js:6:25:6:31 | req.url | execa.js:24:22:24:30 | cmd + arg | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:24:22:24:30 | cmd + arg | execa.js:7:25:7:31 | req.url | execa.js:24:22:24:30 | cmd + arg | This command line depends on a $@. | execa.js:7:25:7:31 | req.url | user-provided value | +| execa.js:11:15:11:17 | cmd | execa.js:6:25:6:31 | req.url | execa.js:11:15:11:17 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:13:32:13:34 | cmd | execa.js:6:25:6:31 | req.url | execa.js:13:32:13:34 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:14:31:14:33 | cmd | execa.js:6:25:6:31 | req.url | execa.js:14:31:14:33 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:17:14:17:16 | cmd | execa.js:6:25:6:31 | req.url | execa.js:17:14:17:16 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:19:32:19:34 | cmd | execa.js:6:25:6:31 | req.url | execa.js:19:32:19:34 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:20:33:20:35 | cmd | execa.js:6:25:6:31 | req.url | execa.js:20:33:20:35 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:23:17:23:19 | cmd | execa.js:6:25:6:31 | req.url | execa.js:23:17:23:19 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:24:17:24:19 | cmd | execa.js:6:25:6:31 | req.url | execa.js:24:17:24:19 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:25:17:25:19 | cmd | execa.js:6:25:6:31 | req.url | execa.js:25:17:25:19 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:26:17:26:19 | cmd | execa.js:6:25:6:31 | req.url | execa.js:26:17:26:19 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:28:15:28:17 | cmd | execa.js:6:25:6:31 | req.url | execa.js:28:15:28:17 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:29:15:29:17 | cmd | execa.js:6:25:6:31 | req.url | execa.js:29:15:29:17 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:31:24:31:47 | cmd + a ... + arg3 | execa.js:6:25:6:31 | req.url | execa.js:31:24:31:47 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:31:24:31:47 | cmd + a ... + arg3 | execa.js:7:26:7:32 | req.url | execa.js:31:24:31:47 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:7:26:7:32 | req.url | user-provided value | +| execa.js:31:24:31:47 | cmd + a ... + arg3 | execa.js:8:26:8:32 | req.url | execa.js:31:24:31:47 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:8:26:8:32 | req.url | user-provided value | +| execa.js:31:24:31:47 | cmd + a ... + arg3 | execa.js:9:26:9:32 | req.url | execa.js:31:24:31:47 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:9:26:9:32 | req.url | user-provided value | +| execa.js:32:24:32:47 | cmd + a ... + arg3 | execa.js:6:25:6:31 | req.url | execa.js:32:24:32:47 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:32:24:32:47 | cmd + a ... + arg3 | execa.js:7:26:7:32 | req.url | execa.js:32:24:32:47 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:7:26:7:32 | req.url | user-provided value | +| execa.js:32:24:32:47 | cmd + a ... + arg3 | execa.js:8:26:8:32 | req.url | execa.js:32:24:32:47 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:8:26:8:32 | req.url | user-provided value | +| execa.js:32:24:32:47 | cmd + a ... + arg3 | execa.js:9:26:9:32 | req.url | execa.js:32:24:32:47 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:9:26:9:32 | req.url | user-provided value | +| execa.js:34:22:34:45 | cmd + a ... + arg3 | execa.js:6:25:6:31 | req.url | execa.js:34:22:34:45 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:34:22:34:45 | cmd + a ... + arg3 | execa.js:7:26:7:32 | req.url | execa.js:34:22:34:45 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:7:26:7:32 | req.url | user-provided value | +| execa.js:34:22:34:45 | cmd + a ... + arg3 | execa.js:8:26:8:32 | req.url | execa.js:34:22:34:45 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:8:26:8:32 | req.url | user-provided value | +| execa.js:34:22:34:45 | cmd + a ... + arg3 | execa.js:9:26:9:32 | req.url | execa.js:34:22:34:45 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:9:26:9:32 | req.url | user-provided value | +| execa.js:35:22:35:45 | cmd + a ... + arg3 | execa.js:6:25:6:31 | req.url | execa.js:35:22:35:45 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | +| execa.js:35:22:35:45 | cmd + a ... + arg3 | execa.js:7:26:7:32 | req.url | execa.js:35:22:35:45 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:7:26:7:32 | req.url | user-provided value | +| execa.js:35:22:35:45 | cmd + a ... + arg3 | execa.js:8:26:8:32 | req.url | execa.js:35:22:35:45 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:8:26:8:32 | req.url | user-provided value | +| execa.js:35:22:35:45 | cmd + a ... + arg3 | execa.js:9:26:9:32 | req.url | execa.js:35:22:35:45 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:9:26:9:32 | req.url | user-provided value | | form-parsers.js:9:8:9:39 | "touch ... nalname | form-parsers.js:9:19:9:26 | req.file | form-parsers.js:9:8:9:39 | "touch ... nalname | This command line depends on a $@. | form-parsers.js:9:19:9:26 | req.file | user-provided value | | form-parsers.js:14:10:14:37 | "touch ... nalname | form-parsers.js:13:3:13:11 | req.files | form-parsers.js:14:10:14:37 | "touch ... nalname | This command line depends on a $@. | form-parsers.js:13:3:13:11 | req.files | user-provided value | | form-parsers.js:25:10:25:28 | "touch " + filename | form-parsers.js:24:48:24:55 | filename | form-parsers.js:25:10:25:28 | "touch " + filename | This command line depends on a $@. | form-parsers.js:24:48:24:55 | filename | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/execa.js b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/execa.js index 5155b2285505..9762f361f48a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/execa.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/execa.js @@ -6,30 +6,31 @@ http.createServer(async function (req, res) { let cmd = url.parse(req.url, true).query["cmd"][0]; let arg1 = url.parse(req.url, true).query["arg1"]; let arg2 = url.parse(req.url, true).query["arg2"]; + let arg3 = url.parse(req.url, true).query["arg3"]; - await $`${cmd} ${arg1} ${arg2}`; // NOT OK - await $`ssh ${arg1} ${arg2}`; // NOT OK - $({ shell: false }).sync`${cmd} ${arg} ${arg} ${arg2}`; // NOT OK - $({ shell: true }).sync`${cmd} ${arg} ${arg} ${arg2}`; // NOT OK - $({ shell: false }).sync`ssh ${arg} ${arg} ${arg2}`; // NOT OK + await $`${cmd} ${arg1} ${arg2} ${arg3}`; // NOT OK + await $`ssh ${arg1} ${arg2} ${arg3}`; // NOT OK + $({ shell: false }).sync`${cmd} ${arg1} ${arg2} ${arg3}`; // NOT OK + $({ shell: true }).sync`${cmd} ${arg1} ${arg2} ${arg3}`; // NOT OK + $({ shell: false }).sync`ssh ${arg1} ${arg2} ${arg3}`; // NOT OK - $.sync`${cmd} ${arg1} ${arg2}`; // NOT OK - $.sync`ssh ${arg1} ${arg2}`; // NOT OK - await $({ shell: true })`${cmd} ${arg1} ${arg2}` // NOT OK - await $({ shell: false })`${cmd} ${arg1} ${arg2}` // NOT OK - await $({ shell: false })`ssh ${arg1} ${arg2}` // NOT OK + $.sync`${cmd} ${arg1} ${arg2} ${arg3}`; // NOT OK + $.sync`ssh ${arg1} ${arg2} ${arg3}`; // NOT OK + await $({ shell: true })`${cmd} ${arg1} ${arg2} ${arg3}` // NOT OK + await $({ shell: false })`${cmd} ${arg1} ${arg2} ${arg3}` // NOT OK + await $({ shell: false })`ssh ${arg1} ${arg2} ${arg3}` // NOT OK - await execa(cmd, [arg1]); // NOT OK + await execa(cmd, [arg1, arg2, arg3]); // NOT OK await execa(cmd, { shell: true }); // NOT OK await execa(cmd, { shell: true }); // NOT OK - await execa(cmd, [arg1], { shell: true }); // NOT OK + await execa(cmd, [arg1, arg2, arg3], { shell: true }); // NOT OK - execaSync(cmd, [arg1]); // NOT OK - execaSync(cmd, [arg1], { shell: true }); // NOT OK + execaSync(cmd, [arg1, arg2, arg3]); // NOT OK + execaSync(cmd, [arg1, arg2, arg3], { shell: true }); // NOT OK - await execaCommand(cmd + arg1); // NOT OK - await execaCommand(cmd + arg1, { shell: true }); // NOT OK + await execaCommand(cmd + arg1 + arg2 + arg3); // NOT OK + await execaCommand(cmd + arg1 + arg2 + arg3, { shell: true }); // NOT OK - execaCommandSync(cmd + arg1); // NOT OK - execaCommandSync(cmd + arg1, { shell: true }); // NOT OK + execaCommandSync(cmd + arg1 + arg2 + arg3); // NOT OK + execaCommandSync(cmd + arg1 + arg2 + arg3, { shell: true }); // NOT OK }); \ No newline at end of file From 67fb802f29dd03c38ec41e484f566a2bedd1a37b Mon Sep 17 00:00:00 2001 From: amammad <77095239+amammad@users.noreply.github.com> Date: Tue, 5 Dec 2023 18:37:50 +0100 Subject: [PATCH 09/10] fix conflict --- .../CWE-022/TaintedPath/TaintedPath.expected | 548 ++++++------------ 1 file changed, 167 insertions(+), 381 deletions(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected index a5e6653291ac..177d6b266ebf 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected @@ -1535,159 +1535,76 @@ nodes | TaintedPath.js:214:35:214:38 | path | | TaintedPath.js:214:35:214:38 | path | | TaintedPath.js:214:35:214:38 | path | -| execa.js:6:9:6:64 | filePath | -| execa.js:6:9:6:64 | filePath | -| execa.js:6:9:6:64 | filePath | -| execa.js:6:9:6:64 | filePath | -| execa.js:6:9:6:64 | filePath | -| execa.js:6:9:6:64 | filePath | -| execa.js:6:9:6:64 | filePath | -| execa.js:6:9:6:64 | filePath | -| execa.js:6:9:6:64 | filePath | -| execa.js:6:9:6:64 | filePath | -| execa.js:6:9:6:64 | filePath | -| execa.js:6:9:6:64 | filePath | -| execa.js:6:9:6:64 | filePath | -| execa.js:6:9:6:64 | filePath | -| execa.js:6:9:6:64 | filePath | -| execa.js:6:9:6:64 | filePath | -| execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:30:6:36 | req.url | -| execa.js:6:30:6:36 | req.url | -| execa.js:6:30:6:36 | req.url | -| execa.js:6:30:6:36 | req.url | -| execa.js:6:30:6:36 | req.url | -| execa.js:9:26:9:33 | filePath | -| execa.js:9:26:9:33 | filePath | -| execa.js:9:26:9:33 | filePath | -| execa.js:9:26:9:33 | filePath | -| execa.js:9:26:9:33 | filePath | -| execa.js:9:26:9:33 | filePath | -| execa.js:9:26:9:33 | filePath | -| execa.js:9:26:9:33 | filePath | -| execa.js:9:26:9:33 | filePath | -| execa.js:9:26:9:33 | filePath | -| execa.js:9:26:9:33 | filePath | -| execa.js:9:26:9:33 | filePath | -| execa.js:9:26:9:33 | filePath | -| execa.js:9:26:9:33 | filePath | -| execa.js:9:26:9:33 | filePath | -| execa.js:9:26:9:33 | filePath | -| execa.js:9:26:9:33 | filePath | -| execa.js:12:37:12:44 | filePath | -| execa.js:12:37:12:44 | filePath | -| execa.js:12:37:12:44 | filePath | -| execa.js:12:37:12:44 | filePath | -| execa.js:12:37:12:44 | filePath | -| execa.js:12:37:12:44 | filePath | -| execa.js:12:37:12:44 | filePath | -| execa.js:12:37:12:44 | filePath | -| execa.js:12:37:12:44 | filePath | -| execa.js:12:37:12:44 | filePath | -| execa.js:12:37:12:44 | filePath | -| execa.js:12:37:12:44 | filePath | -| execa.js:12:37:12:44 | filePath | -| execa.js:12:37:12:44 | filePath | -| execa.js:12:37:12:44 | filePath | -| execa.js:12:37:12:44 | filePath | -| execa.js:12:37:12:44 | filePath | -| execa.js:15:50:15:57 | filePath | -| execa.js:15:50:15:57 | filePath | -| execa.js:15:50:15:57 | filePath | -| execa.js:15:50:15:57 | filePath | -| execa.js:15:50:15:57 | filePath | -| execa.js:15:50:15:57 | filePath | -| execa.js:15:50:15:57 | filePath | -| execa.js:15:50:15:57 | filePath | -| execa.js:15:50:15:57 | filePath | -| execa.js:15:50:15:57 | filePath | -| execa.js:15:50:15:57 | filePath | -| execa.js:15:50:15:57 | filePath | -| execa.js:15:50:15:57 | filePath | -| execa.js:15:50:15:57 | filePath | -| execa.js:15:50:15:57 | filePath | -| execa.js:15:50:15:57 | filePath | -| execa.js:15:50:15:57 | filePath | -| execa.js:18:62:18:69 | filePath | -| execa.js:18:62:18:69 | filePath | -| execa.js:18:62:18:69 | filePath | -| execa.js:18:62:18:69 | filePath | -| execa.js:18:62:18:69 | filePath | -| execa.js:18:62:18:69 | filePath | -| execa.js:18:62:18:69 | filePath | -| execa.js:18:62:18:69 | filePath | -| execa.js:18:62:18:69 | filePath | -| execa.js:18:62:18:69 | filePath | -| execa.js:18:62:18:69 | filePath | -| execa.js:18:62:18:69 | filePath | -| execa.js:18:62:18:69 | filePath | -| execa.js:18:62:18:69 | filePath | -| execa.js:18:62:18:69 | filePath | -| execa.js:18:62:18:69 | filePath | -| execa.js:18:62:18:69 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:28:8:34 | req.url | +| examples/TaintedPath.js:8:28:8:34 | req.url | +| examples/TaintedPath.js:8:28:8:34 | req.url | +| examples/TaintedPath.js:8:28:8:34 | req.url | +| examples/TaintedPath.js:8:28:8:34 | req.url | +| examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | | express.js:8:20:8:32 | req.query.bar | | express.js:8:20:8:32 | req.query.bar | | express.js:8:20:8:32 | req.query.bar | @@ -6788,230 +6705,102 @@ edges | TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | | TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | | TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:9:26:9:33 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:12:37:12:44 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:15:50:15:57 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:9:6:64 | filePath | execa.js:18:62:18:69 | filePath | -| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:43 | url.par ... , true) | execa.js:6:20:6:49 | url.par ... ).query | -| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:49 | url.par ... ).query | execa.js:6:20:6:61 | url.par ... ePath"] | -| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:61 | url.par ... ePath"] | execa.js:6:20:6:64 | url.par ... th"][0] | -| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | -| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | -| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | -| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | -| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | -| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | -| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | -| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | -| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | -| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | -| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | -| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | -| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | -| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | -| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | -| execa.js:6:20:6:64 | url.par ... th"][0] | execa.js:6:9:6:64 | filePath | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | -| execa.js:6:30:6:36 | req.url | execa.js:6:20:6:43 | url.par ... , true) | +| examples/TaintedPath.js:8:7:8:52 | filePath | examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:8:7:8:52 | filePath | examples/TaintedPath.js:11:36:11:43 | filePath | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | examples/TaintedPath.js:8:7:8:52 | filePath | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | +| examples/TaintedPath.js:11:36:11:43 | filePath | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | | express.js:8:20:8:32 | req.query.bar | express.js:8:20:8:32 | req.query.bar | | handlebars.js:10:51:10:58 | filePath | handlebars.js:11:32:11:39 | filePath | | handlebars.js:10:51:10:58 | filePath | handlebars.js:11:32:11:39 | filePath | @@ -10722,10 +10511,7 @@ edges | TaintedPath.js:212:31:212:34 | path | TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:212:31:212:34 | path | This path depends on a $@. | TaintedPath.js:211:24:211:30 | req.url | user-provided value | | TaintedPath.js:213:45:213:48 | path | TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:213:45:213:48 | path | This path depends on a $@. | TaintedPath.js:211:24:211:30 | req.url | user-provided value | | TaintedPath.js:214:35:214:38 | path | TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:214:35:214:38 | path | This path depends on a $@. | TaintedPath.js:211:24:211:30 | req.url | user-provided value | -| execa.js:9:26:9:33 | filePath | execa.js:6:30:6:36 | req.url | execa.js:9:26:9:33 | filePath | This path depends on a $@. | execa.js:6:30:6:36 | req.url | user-provided value | -| execa.js:12:37:12:44 | filePath | execa.js:6:30:6:36 | req.url | execa.js:12:37:12:44 | filePath | This path depends on a $@. | execa.js:6:30:6:36 | req.url | user-provided value | -| execa.js:15:50:15:57 | filePath | execa.js:6:30:6:36 | req.url | execa.js:15:50:15:57 | filePath | This path depends on a $@. | execa.js:6:30:6:36 | req.url | user-provided value | -| execa.js:18:62:18:69 | filePath | execa.js:6:30:6:36 | req.url | execa.js:18:62:18:69 | filePath | This path depends on a $@. | execa.js:6:30:6:36 | req.url | user-provided value | +| examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | This path depends on a $@. | examples/TaintedPath.js:8:28:8:34 | req.url | user-provided value | | express.js:8:20:8:32 | req.query.bar | express.js:8:20:8:32 | req.query.bar | express.js:8:20:8:32 | req.query.bar | This path depends on a $@. | express.js:8:20:8:32 | req.query.bar | user-provided value | | handlebars.js:11:32:11:39 | filePath | handlebars.js:29:46:29:60 | req.params.path | handlebars.js:11:32:11:39 | filePath | This path depends on a $@. | handlebars.js:29:46:29:60 | req.params.path | user-provided value | | handlebars.js:15:25:15:32 | filePath | handlebars.js:43:15:43:29 | req.params.path | handlebars.js:15:25:15:32 | filePath | This path depends on a $@. | handlebars.js:43:15:43:29 | req.params.path | user-provided value | From 1547cd054600ed4fcfdc3670f2914c4eaa3e98d7 Mon Sep 17 00:00:00 2001 From: amammad <77095239+amammad@users.noreply.github.com> Date: Tue, 5 Dec 2023 18:59:46 +0100 Subject: [PATCH 10/10] added inline tests, move to experimental dir --- javascript/ql/lib/javascript.qll | 1 - .../experimental/semmle/javascript}/Execa.qll | 1 - .../Execa/CommandInjection/tests.expected | 22 ++ .../Execa/CommandInjection/tests.js | 36 ++++ .../Execa/CommandInjection/tests.ql | 38 ++++ .../Execa/PathInjection/tests.expected | 6 + .../Execa/PathInjection/tests.js} | 8 +- .../experimental/Execa/PathInjection/tests.ql | 34 +++ .../CommandInjection.expected | 194 ------------------ .../CWE-078/CommandInjection/execa.js | 36 ---- 10 files changed, 140 insertions(+), 236 deletions(-) rename javascript/ql/{lib/semmle/javascript/frameworks => src/experimental/semmle/javascript}/Execa.qll (98%) create mode 100644 javascript/ql/test/experimental/Execa/CommandInjection/tests.expected create mode 100644 javascript/ql/test/experimental/Execa/CommandInjection/tests.js create mode 100644 javascript/ql/test/experimental/Execa/CommandInjection/tests.ql create mode 100644 javascript/ql/test/experimental/Execa/PathInjection/tests.expected rename javascript/ql/test/{query-tests/Security/CWE-022/TaintedPath/execa.js => experimental/Execa/PathInjection/tests.js} (62%) create mode 100644 javascript/ql/test/experimental/Execa/PathInjection/tests.ql delete mode 100644 javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/execa.js diff --git a/javascript/ql/lib/javascript.qll b/javascript/ql/lib/javascript.qll index 238bd870a905..07fb759bd655 100644 --- a/javascript/ql/lib/javascript.qll +++ b/javascript/ql/lib/javascript.qll @@ -123,7 +123,6 @@ import semmle.javascript.frameworks.Request import semmle.javascript.frameworks.RxJS import semmle.javascript.frameworks.ServerLess import semmle.javascript.frameworks.ShellJS -import semmle.javascript.frameworks.Execa import semmle.javascript.frameworks.Snapdragon import semmle.javascript.frameworks.SystemCommandExecutors import semmle.javascript.frameworks.SQL diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll b/javascript/ql/src/experimental/semmle/javascript/Execa.qll similarity index 98% rename from javascript/ql/lib/semmle/javascript/frameworks/Execa.qll rename to javascript/ql/src/experimental/semmle/javascript/Execa.qll index c73b69199578..2f301ae0bf8c 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Execa.qll +++ b/javascript/ql/src/experimental/semmle/javascript/Execa.qll @@ -3,7 +3,6 @@ */ import javascript -import semmle.javascript.security.dataflow.RequestForgeryCustomizations /** * Provide model for [Execa](https://github.com/sindresorhus/execa) package diff --git a/javascript/ql/test/experimental/Execa/CommandInjection/tests.expected b/javascript/ql/test/experimental/Execa/CommandInjection/tests.expected new file mode 100644 index 000000000000..931d1de923f3 --- /dev/null +++ b/javascript/ql/test/experimental/Execa/CommandInjection/tests.expected @@ -0,0 +1,22 @@ +passingPositiveTests +| PASSED | CommandInjection | tests.js:11:46:11:70 | // test ... jection | +| PASSED | CommandInjection | tests.js:12:43:12:67 | // test ... jection | +| PASSED | CommandInjection | tests.js:13:63:13:87 | // test ... jection | +| PASSED | CommandInjection | tests.js:14:62:14:86 | // test ... jection | +| PASSED | CommandInjection | tests.js:15:60:15:84 | // test ... jection | +| PASSED | CommandInjection | tests.js:17:45:17:69 | // test ... jection | +| PASSED | CommandInjection | tests.js:18:42:18:66 | // test ... jection | +| PASSED | CommandInjection | tests.js:19:62:19:86 | // test ... jection | +| PASSED | CommandInjection | tests.js:20:63:20:87 | // test ... jection | +| PASSED | CommandInjection | tests.js:21:60:21:84 | // test ... jection | +| PASSED | CommandInjection | tests.js:23:43:23:67 | // test ... jection | +| PASSED | CommandInjection | tests.js:24:40:24:64 | // test ... jection | +| PASSED | CommandInjection | tests.js:25:40:25:64 | // test ... jection | +| PASSED | CommandInjection | tests.js:26:60:26:84 | // test ... jection | +| PASSED | CommandInjection | tests.js:28:41:28:65 | // test ... jection | +| PASSED | CommandInjection | tests.js:29:58:29:82 | // test ... jection | +| PASSED | CommandInjection | tests.js:31:51:31:75 | // test ... jection | +| PASSED | CommandInjection | tests.js:32:68:32:92 | // test ... jection | +| PASSED | CommandInjection | tests.js:34:49:34:73 | // test ... jection | +| PASSED | CommandInjection | tests.js:35:66:35:90 | // test ... jection | +failingPositiveTests diff --git a/javascript/ql/test/experimental/Execa/CommandInjection/tests.js b/javascript/ql/test/experimental/Execa/CommandInjection/tests.js new file mode 100644 index 000000000000..eb35be96b616 --- /dev/null +++ b/javascript/ql/test/experimental/Execa/CommandInjection/tests.js @@ -0,0 +1,36 @@ +import { execa, execaSync, execaCommand, execaCommandSync, $ } from 'execa'; +import http from 'node:http' +import url from 'url' + +http.createServer(async function (req, res) { + let cmd = url.parse(req.url, true).query["cmd"][0]; + let arg1 = url.parse(req.url, true).query["arg1"]; + let arg2 = url.parse(req.url, true).query["arg2"]; + let arg3 = url.parse(req.url, true).query["arg3"]; + + await $`${cmd} ${arg1} ${arg2} ${arg3}`; // test: CommandInjection + await $`ssh ${arg1} ${arg2} ${arg3}`; // test: CommandInjection + $({ shell: false }).sync`${cmd} ${arg1} ${arg2} ${arg3}`; // test: CommandInjection + $({ shell: true }).sync`${cmd} ${arg1} ${arg2} ${arg3}`; // test: CommandInjection + $({ shell: false }).sync`ssh ${arg1} ${arg2} ${arg3}`; // test: CommandInjection + + $.sync`${cmd} ${arg1} ${arg2} ${arg3}`; // test: CommandInjection + $.sync`ssh ${arg1} ${arg2} ${arg3}`; // test: CommandInjection + await $({ shell: true })`${cmd} ${arg1} ${arg2} ${arg3}` // test: CommandInjection + await $({ shell: false })`${cmd} ${arg1} ${arg2} ${arg3}` // test: CommandInjection + await $({ shell: false })`ssh ${arg1} ${arg2} ${arg3}` // test: CommandInjection + + await execa(cmd, [arg1, arg2, arg3]); // test: CommandInjection + await execa(cmd, { shell: true }); // test: CommandInjection + await execa(cmd, { shell: true }); // test: CommandInjection + await execa(cmd, [arg1, arg2, arg3], { shell: true }); // test: CommandInjection + + execaSync(cmd, [arg1, arg2, arg3]); // test: CommandInjection + execaSync(cmd, [arg1, arg2, arg3], { shell: true }); // test: CommandInjection + + await execaCommand(cmd + arg1 + arg2 + arg3); // test: CommandInjection + await execaCommand(cmd + arg1 + arg2 + arg3, { shell: true }); // test: CommandInjection + + execaCommandSync(cmd + arg1 + arg2 + arg3); // test: CommandInjection + execaCommandSync(cmd + arg1 + arg2 + arg3, { shell: true }); // test: CommandInjection +}); \ No newline at end of file diff --git a/javascript/ql/test/experimental/Execa/CommandInjection/tests.ql b/javascript/ql/test/experimental/Execa/CommandInjection/tests.ql new file mode 100644 index 000000000000..a8ab812f821d --- /dev/null +++ b/javascript/ql/test/experimental/Execa/CommandInjection/tests.ql @@ -0,0 +1,38 @@ +import javascript + +class InlineTest extends LineComment { + string tests; + + InlineTest() { tests = this.getText().regexpCapture("\\s*test:(.*)", 1) } + + string getPositiveTest() { + result = tests.trim().splitAt(",").trim() and not result.matches("!%") + } + + predicate hasPositiveTest(string test) { test = this.getPositiveTest() } + + predicate inNode(DataFlow::Node n) { + this.getLocation().getFile() = n.getFile() and + this.getLocation().getStartLine() = n.getStartLine() + } +} + +import experimental.semmle.javascript.Execa + +query predicate passingPositiveTests(string res, string expectation, InlineTest t) { + res = "PASSED" and + t.hasPositiveTest(expectation) and + expectation = "CommandInjection" and + exists(SystemCommandExecution n | + t.inNode(n.getArgumentList()) or t.inNode(n.getACommandArgument()) + ) +} + +query predicate failingPositiveTests(string res, string expectation, InlineTest t) { + res = "FAILED" and + t.hasPositiveTest(expectation) and + expectation = "CommandInjection" and + not exists(SystemCommandExecution n | + t.inNode(n.getArgumentList()) or t.inNode(n.getACommandArgument()) + ) +} diff --git a/javascript/ql/test/experimental/Execa/PathInjection/tests.expected b/javascript/ql/test/experimental/Execa/PathInjection/tests.expected new file mode 100644 index 000000000000..3149ae1c0220 --- /dev/null +++ b/javascript/ql/test/experimental/Execa/PathInjection/tests.expected @@ -0,0 +1,6 @@ +passingPositiveTests +| PASSED | PathInjection | tests.js:9:43:9:64 | // test ... jection | +| PASSED | PathInjection | tests.js:12:50:12:71 | // test ... jection | +| PASSED | PathInjection | tests.js:15:61:15:82 | // test ... jection | +| PASSED | PathInjection | tests.js:18:73:18:94 | // test ... jection | +failingPositiveTests diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/execa.js b/javascript/ql/test/experimental/Execa/PathInjection/tests.js similarity index 62% rename from javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/execa.js rename to javascript/ql/test/experimental/Execa/PathInjection/tests.js index b246f6c384ef..4665b8c89507 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/execa.js +++ b/javascript/ql/test/experimental/Execa/PathInjection/tests.js @@ -6,14 +6,14 @@ http.createServer(async function (req, res) { let filePath = url.parse(req.url, true).query["filePath"][0]; // Piping to stdin from a file - await $({ inputFile: filePath })`cat` // NOT OK + await $({ inputFile: filePath })`cat` // test: PathInjection // Piping to stdin from a file - await execa('cat', { inputFile: filePath }); // NOT OK + await execa('cat', { inputFile: filePath }); // test: PathInjection // Piping Stdout to file - await execa('echo', ['example3']).pipeStdout(filePath); // NOT OK + await execa('echo', ['example3']).pipeStdout(filePath); // test: PathInjection // Piping all of command output to file - await execa('echo', ['example4'], { all: true }).pipeAll(filePath); // NOT OK + await execa('echo', ['example4'], { all: true }).pipeAll(filePath); // test: PathInjection }); \ No newline at end of file diff --git a/javascript/ql/test/experimental/Execa/PathInjection/tests.ql b/javascript/ql/test/experimental/Execa/PathInjection/tests.ql new file mode 100644 index 000000000000..08b5435e01f5 --- /dev/null +++ b/javascript/ql/test/experimental/Execa/PathInjection/tests.ql @@ -0,0 +1,34 @@ +import javascript + +class InlineTest extends LineComment { + string tests; + + InlineTest() { tests = this.getText().regexpCapture("\\s*test:(.*)", 1) } + + string getPositiveTest() { + result = tests.trim().splitAt(",").trim() and not result.matches("!%") + } + + predicate hasPositiveTest(string test) { test = this.getPositiveTest() } + + predicate inNode(DataFlow::Node n) { + this.getLocation().getFile() = n.getFile() and + this.getLocation().getStartLine() = n.getStartLine() + } +} + +import experimental.semmle.javascript.Execa + +query predicate passingPositiveTests(string res, string expectation, InlineTest t) { + res = "PASSED" and + t.hasPositiveTest(expectation) and + expectation = "PathInjection" and + exists(FileSystemReadAccess n | t.inNode(n.getAPathArgument())) +} + +query predicate failingPositiveTests(string res, string expectation, InlineTest t) { + res = "FAILED" and + t.hasPositiveTest(expectation) and + expectation = "PathInjection" and + not exists(FileSystemReadAccess n | t.inNode(n.getAPathArgument())) +} diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/CommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/CommandInjection.expected index 20fa7f652796..fb8bc60e6736 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/CommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/CommandInjection.expected @@ -103,79 +103,6 @@ nodes | execSeries.js:18:34:18:40 | req.url | | execSeries.js:19:12:19:16 | [cmd] | | execSeries.js:19:13:19:15 | cmd | -| execa.js:6:9:6:54 | cmd | -| execa.js:6:15:6:38 | url.par ... , true) | -| execa.js:6:15:6:44 | url.par ... ).query | -| execa.js:6:15:6:51 | url.par ... ["cmd"] | -| execa.js:6:15:6:54 | url.par ... md"][0] | -| execa.js:6:25:6:31 | req.url | -| execa.js:6:25:6:31 | req.url | -| execa.js:7:9:7:53 | arg1 | -| execa.js:7:16:7:39 | url.par ... , true) | -| execa.js:7:16:7:45 | url.par ... ).query | -| execa.js:7:16:7:53 | url.par ... "arg1"] | -| execa.js:7:26:7:32 | req.url | -| execa.js:7:26:7:32 | req.url | -| execa.js:8:9:8:53 | arg2 | -| execa.js:8:16:8:39 | url.par ... , true) | -| execa.js:8:16:8:45 | url.par ... ).query | -| execa.js:8:16:8:53 | url.par ... "arg2"] | -| execa.js:8:26:8:32 | req.url | -| execa.js:8:26:8:32 | req.url | -| execa.js:9:9:9:53 | arg3 | -| execa.js:9:16:9:39 | url.par ... , true) | -| execa.js:9:16:9:45 | url.par ... ).query | -| execa.js:9:16:9:53 | url.par ... "arg3"] | -| execa.js:9:26:9:32 | req.url | -| execa.js:9:26:9:32 | req.url | -| execa.js:11:15:11:17 | cmd | -| execa.js:11:15:11:17 | cmd | -| execa.js:13:32:13:34 | cmd | -| execa.js:13:32:13:34 | cmd | -| execa.js:14:31:14:33 | cmd | -| execa.js:14:31:14:33 | cmd | -| execa.js:17:14:17:16 | cmd | -| execa.js:17:14:17:16 | cmd | -| execa.js:19:32:19:34 | cmd | -| execa.js:19:32:19:34 | cmd | -| execa.js:20:33:20:35 | cmd | -| execa.js:20:33:20:35 | cmd | -| execa.js:23:17:23:19 | cmd | -| execa.js:23:17:23:19 | cmd | -| execa.js:24:17:24:19 | cmd | -| execa.js:24:17:24:19 | cmd | -| execa.js:25:17:25:19 | cmd | -| execa.js:25:17:25:19 | cmd | -| execa.js:26:17:26:19 | cmd | -| execa.js:26:17:26:19 | cmd | -| execa.js:28:15:28:17 | cmd | -| execa.js:28:15:28:17 | cmd | -| execa.js:29:15:29:17 | cmd | -| execa.js:29:15:29:17 | cmd | -| execa.js:31:24:31:26 | cmd | -| execa.js:31:24:31:47 | cmd + a ... + arg3 | -| execa.js:31:24:31:47 | cmd + a ... + arg3 | -| execa.js:31:30:31:33 | arg1 | -| execa.js:31:37:31:40 | arg2 | -| execa.js:31:44:31:47 | arg3 | -| execa.js:32:24:32:26 | cmd | -| execa.js:32:24:32:47 | cmd + a ... + arg3 | -| execa.js:32:24:32:47 | cmd + a ... + arg3 | -| execa.js:32:30:32:33 | arg1 | -| execa.js:32:37:32:40 | arg2 | -| execa.js:32:44:32:47 | arg3 | -| execa.js:34:22:34:24 | cmd | -| execa.js:34:22:34:45 | cmd + a ... + arg3 | -| execa.js:34:22:34:45 | cmd + a ... + arg3 | -| execa.js:34:28:34:31 | arg1 | -| execa.js:34:35:34:38 | arg2 | -| execa.js:34:42:34:45 | arg3 | -| execa.js:35:22:35:24 | cmd | -| execa.js:35:22:35:45 | cmd + a ... + arg3 | -| execa.js:35:22:35:45 | cmd + a ... + arg3 | -| execa.js:35:28:35:31 | arg1 | -| execa.js:35:35:35:38 | arg2 | -| execa.js:35:42:35:45 | arg3 | | form-parsers.js:9:8:9:39 | "touch ... nalname | | form-parsers.js:9:8:9:39 | "touch ... nalname | | form-parsers.js:9:19:9:26 | req.file | @@ -359,99 +286,6 @@ edges | execSeries.js:18:34:18:40 | req.url | execSeries.js:18:13:18:47 | require ... , true) | | execSeries.js:19:12:19:16 | [cmd] | execSeries.js:13:19:13:26 | commands | | execSeries.js:19:13:19:15 | cmd | execSeries.js:19:12:19:16 | [cmd] | -| execa.js:6:9:6:54 | cmd | execa.js:11:15:11:17 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:11:15:11:17 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:13:32:13:34 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:13:32:13:34 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:14:31:14:33 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:14:31:14:33 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:17:14:17:16 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:17:14:17:16 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:19:32:19:34 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:19:32:19:34 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:20:33:20:35 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:20:33:20:35 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:23:17:23:19 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:23:17:23:19 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:24:17:24:19 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:24:17:24:19 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:25:17:25:19 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:25:17:25:19 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:26:17:26:19 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:26:17:26:19 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:28:15:28:17 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:28:15:28:17 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:29:15:29:17 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:29:15:29:17 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:31:24:31:26 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:32:24:32:26 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:34:22:34:24 | cmd | -| execa.js:6:9:6:54 | cmd | execa.js:35:22:35:24 | cmd | -| execa.js:6:15:6:38 | url.par ... , true) | execa.js:6:15:6:44 | url.par ... ).query | -| execa.js:6:15:6:44 | url.par ... ).query | execa.js:6:15:6:51 | url.par ... ["cmd"] | -| execa.js:6:15:6:51 | url.par ... ["cmd"] | execa.js:6:15:6:54 | url.par ... md"][0] | -| execa.js:6:15:6:54 | url.par ... md"][0] | execa.js:6:9:6:54 | cmd | -| execa.js:6:25:6:31 | req.url | execa.js:6:15:6:38 | url.par ... , true) | -| execa.js:6:25:6:31 | req.url | execa.js:6:15:6:38 | url.par ... , true) | -| execa.js:7:9:7:53 | arg1 | execa.js:31:30:31:33 | arg1 | -| execa.js:7:9:7:53 | arg1 | execa.js:32:30:32:33 | arg1 | -| execa.js:7:9:7:53 | arg1 | execa.js:34:28:34:31 | arg1 | -| execa.js:7:9:7:53 | arg1 | execa.js:35:28:35:31 | arg1 | -| execa.js:7:16:7:39 | url.par ... , true) | execa.js:7:16:7:45 | url.par ... ).query | -| execa.js:7:16:7:45 | url.par ... ).query | execa.js:7:16:7:53 | url.par ... "arg1"] | -| execa.js:7:16:7:53 | url.par ... "arg1"] | execa.js:7:9:7:53 | arg1 | -| execa.js:7:26:7:32 | req.url | execa.js:7:16:7:39 | url.par ... , true) | -| execa.js:7:26:7:32 | req.url | execa.js:7:16:7:39 | url.par ... , true) | -| execa.js:8:9:8:53 | arg2 | execa.js:31:37:31:40 | arg2 | -| execa.js:8:9:8:53 | arg2 | execa.js:32:37:32:40 | arg2 | -| execa.js:8:9:8:53 | arg2 | execa.js:34:35:34:38 | arg2 | -| execa.js:8:9:8:53 | arg2 | execa.js:35:35:35:38 | arg2 | -| execa.js:8:16:8:39 | url.par ... , true) | execa.js:8:16:8:45 | url.par ... ).query | -| execa.js:8:16:8:45 | url.par ... ).query | execa.js:8:16:8:53 | url.par ... "arg2"] | -| execa.js:8:16:8:53 | url.par ... "arg2"] | execa.js:8:9:8:53 | arg2 | -| execa.js:8:26:8:32 | req.url | execa.js:8:16:8:39 | url.par ... , true) | -| execa.js:8:26:8:32 | req.url | execa.js:8:16:8:39 | url.par ... , true) | -| execa.js:9:9:9:53 | arg3 | execa.js:31:44:31:47 | arg3 | -| execa.js:9:9:9:53 | arg3 | execa.js:32:44:32:47 | arg3 | -| execa.js:9:9:9:53 | arg3 | execa.js:34:42:34:45 | arg3 | -| execa.js:9:9:9:53 | arg3 | execa.js:35:42:35:45 | arg3 | -| execa.js:9:16:9:39 | url.par ... , true) | execa.js:9:16:9:45 | url.par ... ).query | -| execa.js:9:16:9:45 | url.par ... ).query | execa.js:9:16:9:53 | url.par ... "arg3"] | -| execa.js:9:16:9:53 | url.par ... "arg3"] | execa.js:9:9:9:53 | arg3 | -| execa.js:9:26:9:32 | req.url | execa.js:9:16:9:39 | url.par ... , true) | -| execa.js:9:26:9:32 | req.url | execa.js:9:16:9:39 | url.par ... , true) | -| execa.js:31:24:31:26 | cmd | execa.js:31:24:31:47 | cmd + a ... + arg3 | -| execa.js:31:24:31:26 | cmd | execa.js:31:24:31:47 | cmd + a ... + arg3 | -| execa.js:31:30:31:33 | arg1 | execa.js:31:24:31:47 | cmd + a ... + arg3 | -| execa.js:31:30:31:33 | arg1 | execa.js:31:24:31:47 | cmd + a ... + arg3 | -| execa.js:31:37:31:40 | arg2 | execa.js:31:24:31:47 | cmd + a ... + arg3 | -| execa.js:31:37:31:40 | arg2 | execa.js:31:24:31:47 | cmd + a ... + arg3 | -| execa.js:31:44:31:47 | arg3 | execa.js:31:24:31:47 | cmd + a ... + arg3 | -| execa.js:31:44:31:47 | arg3 | execa.js:31:24:31:47 | cmd + a ... + arg3 | -| execa.js:32:24:32:26 | cmd | execa.js:32:24:32:47 | cmd + a ... + arg3 | -| execa.js:32:24:32:26 | cmd | execa.js:32:24:32:47 | cmd + a ... + arg3 | -| execa.js:32:30:32:33 | arg1 | execa.js:32:24:32:47 | cmd + a ... + arg3 | -| execa.js:32:30:32:33 | arg1 | execa.js:32:24:32:47 | cmd + a ... + arg3 | -| execa.js:32:37:32:40 | arg2 | execa.js:32:24:32:47 | cmd + a ... + arg3 | -| execa.js:32:37:32:40 | arg2 | execa.js:32:24:32:47 | cmd + a ... + arg3 | -| execa.js:32:44:32:47 | arg3 | execa.js:32:24:32:47 | cmd + a ... + arg3 | -| execa.js:32:44:32:47 | arg3 | execa.js:32:24:32:47 | cmd + a ... + arg3 | -| execa.js:34:22:34:24 | cmd | execa.js:34:22:34:45 | cmd + a ... + arg3 | -| execa.js:34:22:34:24 | cmd | execa.js:34:22:34:45 | cmd + a ... + arg3 | -| execa.js:34:28:34:31 | arg1 | execa.js:34:22:34:45 | cmd + a ... + arg3 | -| execa.js:34:28:34:31 | arg1 | execa.js:34:22:34:45 | cmd + a ... + arg3 | -| execa.js:34:35:34:38 | arg2 | execa.js:34:22:34:45 | cmd + a ... + arg3 | -| execa.js:34:35:34:38 | arg2 | execa.js:34:22:34:45 | cmd + a ... + arg3 | -| execa.js:34:42:34:45 | arg3 | execa.js:34:22:34:45 | cmd + a ... + arg3 | -| execa.js:34:42:34:45 | arg3 | execa.js:34:22:34:45 | cmd + a ... + arg3 | -| execa.js:35:22:35:24 | cmd | execa.js:35:22:35:45 | cmd + a ... + arg3 | -| execa.js:35:22:35:24 | cmd | execa.js:35:22:35:45 | cmd + a ... + arg3 | -| execa.js:35:28:35:31 | arg1 | execa.js:35:22:35:45 | cmd + a ... + arg3 | -| execa.js:35:28:35:31 | arg1 | execa.js:35:22:35:45 | cmd + a ... + arg3 | -| execa.js:35:35:35:38 | arg2 | execa.js:35:22:35:45 | cmd + a ... + arg3 | -| execa.js:35:35:35:38 | arg2 | execa.js:35:22:35:45 | cmd + a ... + arg3 | -| execa.js:35:42:35:45 | arg3 | execa.js:35:22:35:45 | cmd + a ... + arg3 | -| execa.js:35:42:35:45 | arg3 | execa.js:35:22:35:45 | cmd + a ... + arg3 | | form-parsers.js:9:19:9:26 | req.file | form-parsers.js:9:19:9:39 | req.fil ... nalname | | form-parsers.js:9:19:9:26 | req.file | form-parsers.js:9:19:9:39 | req.fil ... nalname | | form-parsers.js:9:19:9:39 | req.fil ... nalname | form-parsers.js:9:8:9:39 | "touch ... nalname | @@ -557,34 +391,6 @@ edges | exec-sh2.js:10:12:10:57 | cp.spaw ... ptions) | exec-sh2.js:14:25:14:31 | req.url | exec-sh2.js:10:40:10:46 | command | This command line depends on a $@. | exec-sh2.js:14:25:14:31 | req.url | user-provided value | | exec-sh.js:15:12:15:61 | cp.spaw ... ptions) | exec-sh.js:19:25:19:31 | req.url | exec-sh.js:15:44:15:50 | command | This command line depends on a $@. | exec-sh.js:19:25:19:31 | req.url | user-provided value | | execSeries.js:14:41:14:47 | command | execSeries.js:18:34:18:40 | req.url | execSeries.js:14:41:14:47 | command | This command line depends on a $@. | execSeries.js:18:34:18:40 | req.url | user-provided value | -| execa.js:11:15:11:17 | cmd | execa.js:6:25:6:31 | req.url | execa.js:11:15:11:17 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:13:32:13:34 | cmd | execa.js:6:25:6:31 | req.url | execa.js:13:32:13:34 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:14:31:14:33 | cmd | execa.js:6:25:6:31 | req.url | execa.js:14:31:14:33 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:17:14:17:16 | cmd | execa.js:6:25:6:31 | req.url | execa.js:17:14:17:16 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:19:32:19:34 | cmd | execa.js:6:25:6:31 | req.url | execa.js:19:32:19:34 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:20:33:20:35 | cmd | execa.js:6:25:6:31 | req.url | execa.js:20:33:20:35 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:23:17:23:19 | cmd | execa.js:6:25:6:31 | req.url | execa.js:23:17:23:19 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:24:17:24:19 | cmd | execa.js:6:25:6:31 | req.url | execa.js:24:17:24:19 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:25:17:25:19 | cmd | execa.js:6:25:6:31 | req.url | execa.js:25:17:25:19 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:26:17:26:19 | cmd | execa.js:6:25:6:31 | req.url | execa.js:26:17:26:19 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:28:15:28:17 | cmd | execa.js:6:25:6:31 | req.url | execa.js:28:15:28:17 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:29:15:29:17 | cmd | execa.js:6:25:6:31 | req.url | execa.js:29:15:29:17 | cmd | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:31:24:31:47 | cmd + a ... + arg3 | execa.js:6:25:6:31 | req.url | execa.js:31:24:31:47 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:31:24:31:47 | cmd + a ... + arg3 | execa.js:7:26:7:32 | req.url | execa.js:31:24:31:47 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:7:26:7:32 | req.url | user-provided value | -| execa.js:31:24:31:47 | cmd + a ... + arg3 | execa.js:8:26:8:32 | req.url | execa.js:31:24:31:47 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:8:26:8:32 | req.url | user-provided value | -| execa.js:31:24:31:47 | cmd + a ... + arg3 | execa.js:9:26:9:32 | req.url | execa.js:31:24:31:47 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:9:26:9:32 | req.url | user-provided value | -| execa.js:32:24:32:47 | cmd + a ... + arg3 | execa.js:6:25:6:31 | req.url | execa.js:32:24:32:47 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:32:24:32:47 | cmd + a ... + arg3 | execa.js:7:26:7:32 | req.url | execa.js:32:24:32:47 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:7:26:7:32 | req.url | user-provided value | -| execa.js:32:24:32:47 | cmd + a ... + arg3 | execa.js:8:26:8:32 | req.url | execa.js:32:24:32:47 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:8:26:8:32 | req.url | user-provided value | -| execa.js:32:24:32:47 | cmd + a ... + arg3 | execa.js:9:26:9:32 | req.url | execa.js:32:24:32:47 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:9:26:9:32 | req.url | user-provided value | -| execa.js:34:22:34:45 | cmd + a ... + arg3 | execa.js:6:25:6:31 | req.url | execa.js:34:22:34:45 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:34:22:34:45 | cmd + a ... + arg3 | execa.js:7:26:7:32 | req.url | execa.js:34:22:34:45 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:7:26:7:32 | req.url | user-provided value | -| execa.js:34:22:34:45 | cmd + a ... + arg3 | execa.js:8:26:8:32 | req.url | execa.js:34:22:34:45 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:8:26:8:32 | req.url | user-provided value | -| execa.js:34:22:34:45 | cmd + a ... + arg3 | execa.js:9:26:9:32 | req.url | execa.js:34:22:34:45 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:9:26:9:32 | req.url | user-provided value | -| execa.js:35:22:35:45 | cmd + a ... + arg3 | execa.js:6:25:6:31 | req.url | execa.js:35:22:35:45 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:6:25:6:31 | req.url | user-provided value | -| execa.js:35:22:35:45 | cmd + a ... + arg3 | execa.js:7:26:7:32 | req.url | execa.js:35:22:35:45 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:7:26:7:32 | req.url | user-provided value | -| execa.js:35:22:35:45 | cmd + a ... + arg3 | execa.js:8:26:8:32 | req.url | execa.js:35:22:35:45 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:8:26:8:32 | req.url | user-provided value | -| execa.js:35:22:35:45 | cmd + a ... + arg3 | execa.js:9:26:9:32 | req.url | execa.js:35:22:35:45 | cmd + a ... + arg3 | This command line depends on a $@. | execa.js:9:26:9:32 | req.url | user-provided value | | form-parsers.js:9:8:9:39 | "touch ... nalname | form-parsers.js:9:19:9:26 | req.file | form-parsers.js:9:8:9:39 | "touch ... nalname | This command line depends on a $@. | form-parsers.js:9:19:9:26 | req.file | user-provided value | | form-parsers.js:14:10:14:37 | "touch ... nalname | form-parsers.js:13:3:13:11 | req.files | form-parsers.js:14:10:14:37 | "touch ... nalname | This command line depends on a $@. | form-parsers.js:13:3:13:11 | req.files | user-provided value | | form-parsers.js:25:10:25:28 | "touch " + filename | form-parsers.js:24:48:24:55 | filename | form-parsers.js:25:10:25:28 | "touch " + filename | This command line depends on a $@. | form-parsers.js:24:48:24:55 | filename | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/execa.js b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/execa.js deleted file mode 100644 index 9762f361f48a..000000000000 --- a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/execa.js +++ /dev/null @@ -1,36 +0,0 @@ -import { execa, execaSync, execaCommand, execaCommandSync, $ } from 'execa'; -import http from 'node:http' -import url from 'url' - -http.createServer(async function (req, res) { - let cmd = url.parse(req.url, true).query["cmd"][0]; - let arg1 = url.parse(req.url, true).query["arg1"]; - let arg2 = url.parse(req.url, true).query["arg2"]; - let arg3 = url.parse(req.url, true).query["arg3"]; - - await $`${cmd} ${arg1} ${arg2} ${arg3}`; // NOT OK - await $`ssh ${arg1} ${arg2} ${arg3}`; // NOT OK - $({ shell: false }).sync`${cmd} ${arg1} ${arg2} ${arg3}`; // NOT OK - $({ shell: true }).sync`${cmd} ${arg1} ${arg2} ${arg3}`; // NOT OK - $({ shell: false }).sync`ssh ${arg1} ${arg2} ${arg3}`; // NOT OK - - $.sync`${cmd} ${arg1} ${arg2} ${arg3}`; // NOT OK - $.sync`ssh ${arg1} ${arg2} ${arg3}`; // NOT OK - await $({ shell: true })`${cmd} ${arg1} ${arg2} ${arg3}` // NOT OK - await $({ shell: false })`${cmd} ${arg1} ${arg2} ${arg3}` // NOT OK - await $({ shell: false })`ssh ${arg1} ${arg2} ${arg3}` // NOT OK - - await execa(cmd, [arg1, arg2, arg3]); // NOT OK - await execa(cmd, { shell: true }); // NOT OK - await execa(cmd, { shell: true }); // NOT OK - await execa(cmd, [arg1, arg2, arg3], { shell: true }); // NOT OK - - execaSync(cmd, [arg1, arg2, arg3]); // NOT OK - execaSync(cmd, [arg1, arg2, arg3], { shell: true }); // NOT OK - - await execaCommand(cmd + arg1 + arg2 + arg3); // NOT OK - await execaCommand(cmd + arg1 + arg2 + arg3, { shell: true }); // NOT OK - - execaCommandSync(cmd + arg1 + arg2 + arg3); // NOT OK - execaCommandSync(cmd + arg1 + arg2 + arg3, { shell: true }); // NOT OK -}); \ No newline at end of file