diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index 592e1a7f2e85..720e513fab6e 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -881,14 +881,29 @@ class PathNode extends TPathNode { /** Gets the summary of the path underlying this path node. */ PathSummary getPathSummary() { result = summary } - /** Gets a successor node of this path node. */ - PathNode getASuccessor() { + /** + * Gets a successor node of this path node, including hidden nodes. + */ + private PathNode getASuccessorInternal() { exists(DataFlow::Node succ, PathSummary newSummary | flowStep(nd, id(cfg), succ, newSummary) and result = MkPathNode(succ, id(cfg), summary.append(newSummary)) ) } + /** + * Gets a successor of this path node, if it is a hidden node. + */ + private PathNode getAHiddenSuccessor() { + isHidden() and + result = getASuccessorInternal() + } + + /** Gets a successor node of this path node. */ + PathNode getASuccessor() { + result = getASuccessorInternal().getAHiddenSuccessor*() + } + /** Gets a textual representation of this path node. */ string toString() { result = nd.toString() } @@ -904,6 +919,19 @@ class PathNode extends TPathNode { ) { nd.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } + + /** + * Holds if this node is hidden from paths in path explanation queries, except + * in cases where it is the source or sink. + */ + predicate isHidden() { + // Skip phi, refinement, and capture nodes + nd.(DataFlow::SsaDefinitionNode).getSsaVariable().getDefinition() instanceof SsaImplicitDefinition + or + // Skip to the top of big left-leaning string concatenation trees. + nd = any(AddExpr add).flow() and + nd = any(AddExpr add).getAnOperand().flow() + } } /** @@ -925,7 +953,11 @@ class SinkPathNode extends PathNode { */ module PathGraph { /** Holds if `nd` is a node in the graph of data flow path explanations. */ - query predicate nodes(PathNode nd) { any() } + query predicate nodes(PathNode nd) { + not nd.isHidden() or + nd instanceof SourcePathNode or + nd instanceof SinkPathNode + } /** Holds if `pred` → `succ` is an edge in the graph of data flow path explanations. */ query predicate edges(PathNode pred, PathNode succ) { pred.getASuccessor() = succ } 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 4bce1e7ce08e..2d9ebccad618 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 @@ -17,14 +17,6 @@ nodes | TaintedPath.js:19:33:19:36 | path | | TaintedPath.js:23:33:23:36 | path | | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:30:7:30:24 | path | -| TaintedPath.js:34:3:34:3 | path | -| TaintedPath.js:34:7:34:24 | path | -| TaintedPath.js:34:29:34:46 | path | -| TaintedPath.js:38:3:38:3 | path | -| TaintedPath.js:38:7:38:24 | path | -| TaintedPath.js:38:29:38:46 | path | -| TaintedPath.js:39:5:39:5 | path | | TaintedPath.js:39:31:39:34 | path | | TaintedPath.js:45:3:45:44 | path | | TaintedPath.js:45:10:45:33 | url.par ... , true) | @@ -112,18 +104,54 @@ edges | TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | | TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | | TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:7:30:24 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:34:3:34:3 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:34:7:34:24 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:34:29:34:46 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:38:3:38:3 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:38:7:38:24 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:38:29:38:46 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:5:39:5 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | | TaintedPath.js:9:14:9:37 | url.par ... , true) | TaintedPath.js:9:14:9:43 | url.par ... ).query | | TaintedPath.js:9:14:9:43 | url.par ... ).query | TaintedPath.js:9:14:9:48 | url.par ... ry.path | | TaintedPath.js:9:14:9:48 | url.par ... ry.path | TaintedPath.js:9:7:9:48 | path | | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:9:14:9:37 | url.par ... , true) | | TaintedPath.js:15:45:15:48 | path | TaintedPath.js:15:29:15:48 | "/home/user/" + path | | TaintedPath.js:30:7:30:24 | path | TaintedPath.js:34:3:34:3 | path | +| TaintedPath.js:30:7:30:24 | path | TaintedPath.js:34:7:34:24 | path | +| TaintedPath.js:30:7:30:24 | path | TaintedPath.js:34:29:34:46 | path | +| TaintedPath.js:30:7:30:24 | path | TaintedPath.js:38:3:38:3 | path | +| TaintedPath.js:30:7:30:24 | path | TaintedPath.js:38:7:38:24 | path | +| TaintedPath.js:30:7:30:24 | path | TaintedPath.js:38:29:38:46 | path | +| TaintedPath.js:30:7:30:24 | path | TaintedPath.js:39:5:39:5 | path | +| TaintedPath.js:30:7:30:24 | path | TaintedPath.js:39:31:39:34 | path | | TaintedPath.js:34:3:34:3 | path | TaintedPath.js:34:7:34:24 | path | +| TaintedPath.js:34:3:34:3 | path | TaintedPath.js:34:29:34:46 | path | +| TaintedPath.js:34:3:34:3 | path | TaintedPath.js:38:3:38:3 | path | +| TaintedPath.js:34:3:34:3 | path | TaintedPath.js:38:7:38:24 | path | +| TaintedPath.js:34:3:34:3 | path | TaintedPath.js:38:29:38:46 | path | +| TaintedPath.js:34:3:34:3 | path | TaintedPath.js:39:5:39:5 | path | +| TaintedPath.js:34:3:34:3 | path | TaintedPath.js:39:31:39:34 | path | | TaintedPath.js:34:7:34:24 | path | TaintedPath.js:34:29:34:46 | path | +| TaintedPath.js:34:7:34:24 | path | TaintedPath.js:38:3:38:3 | path | +| TaintedPath.js:34:7:34:24 | path | TaintedPath.js:38:7:38:24 | path | +| TaintedPath.js:34:7:34:24 | path | TaintedPath.js:38:29:38:46 | path | +| TaintedPath.js:34:7:34:24 | path | TaintedPath.js:39:5:39:5 | path | +| TaintedPath.js:34:7:34:24 | path | TaintedPath.js:39:31:39:34 | path | | TaintedPath.js:34:29:34:46 | path | TaintedPath.js:38:3:38:3 | path | +| TaintedPath.js:34:29:34:46 | path | TaintedPath.js:38:7:38:24 | path | +| TaintedPath.js:34:29:34:46 | path | TaintedPath.js:38:29:38:46 | path | +| TaintedPath.js:34:29:34:46 | path | TaintedPath.js:39:5:39:5 | path | +| TaintedPath.js:34:29:34:46 | path | TaintedPath.js:39:31:39:34 | path | | TaintedPath.js:38:3:38:3 | path | TaintedPath.js:38:7:38:24 | path | +| TaintedPath.js:38:3:38:3 | path | TaintedPath.js:38:29:38:46 | path | +| TaintedPath.js:38:3:38:3 | path | TaintedPath.js:39:5:39:5 | path | +| TaintedPath.js:38:3:38:3 | path | TaintedPath.js:39:31:39:34 | path | | TaintedPath.js:38:7:38:24 | path | TaintedPath.js:38:29:38:46 | path | +| TaintedPath.js:38:7:38:24 | path | TaintedPath.js:39:5:39:5 | path | +| TaintedPath.js:38:7:38:24 | path | TaintedPath.js:39:31:39:34 | path | | TaintedPath.js:38:29:38:46 | path | TaintedPath.js:39:5:39:5 | path | +| TaintedPath.js:38:29:38:46 | path | TaintedPath.js:39:31:39:34 | path | | TaintedPath.js:39:5:39:5 | path | TaintedPath.js:39:31:39:34 | path | | TaintedPath.js:45:3:45:44 | path | TaintedPath.js:47:49:47:52 | path | | TaintedPath.js:45:3:45:44 | path | TaintedPath.js:49:48:49:51 | path | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index 26e61050a275..a5f42fc5e3d5 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -11,14 +11,12 @@ nodes | child_process-test.js:21:14:21:16 | cmd | | child_process-test.js:22:18:22:20 | cmd | | child_process-test.js:23:13:23:15 | cmd | -| child_process-test.js:25:13:25:23 | "foo" + cmd | | child_process-test.js:25:13:25:31 | "foo" + cmd + "bar" | | child_process-test.js:25:21:25:23 | cmd | | child_process-test.js:36:7:36:20 | sh | | child_process-test.js:36:12:36:20 | 'cmd.exe' | | child_process-test.js:38:7:38:20 | sh | | child_process-test.js:38:12:38:20 | '/bin/sh' | -| child_process-test.js:39:5:39:5 | sh | | child_process-test.js:39:14:39:15 | sh | | child_process-test.js:39:18:39:30 | [ flag, cmd ] | | child_process-test.js:39:26:39:28 | cmd | @@ -39,7 +37,6 @@ nodes | child_process-test.js:56:12:56:14 | cmd | | child_process-test.js:56:17:56:20 | args | | execSeries.js:3:20:3:22 | arr | -| execSeries.js:5:4:5:3 | arr | | execSeries.js:6:14:6:16 | arr | | execSeries.js:6:14:6:21 | arr[i++] | | execSeries.js:13:19:13:26 | commands | @@ -71,9 +68,12 @@ edges | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:6:15:6:38 | url.par ... , true) | | child_process-test.js:25:13:25:23 | "foo" + cmd | child_process-test.js:25:13:25:31 | "foo" + cmd + "bar" | | child_process-test.js:25:21:25:23 | cmd | child_process-test.js:25:13:25:23 | "foo" + cmd | +| child_process-test.js:25:21:25:23 | cmd | child_process-test.js:25:13:25:31 | "foo" + cmd + "bar" | | child_process-test.js:36:7:36:20 | sh | child_process-test.js:39:5:39:5 | sh | +| child_process-test.js:36:7:36:20 | sh | child_process-test.js:39:14:39:15 | sh | | child_process-test.js:36:12:36:20 | 'cmd.exe' | child_process-test.js:36:7:36:20 | sh | | child_process-test.js:38:7:38:20 | sh | child_process-test.js:39:5:39:5 | sh | +| child_process-test.js:38:7:38:20 | sh | child_process-test.js:39:14:39:15 | sh | | child_process-test.js:38:12:38:20 | '/bin/sh' | child_process-test.js:38:7:38:20 | sh | | child_process-test.js:39:5:39:5 | sh | child_process-test.js:39:14:39:15 | sh | | child_process-test.js:41:9:41:17 | args | child_process-test.js:44:30:44:33 | args | @@ -86,6 +86,7 @@ edges | child_process-test.js:55:14:55:16 | cmd | child_process-test.js:56:12:56:14 | cmd | | child_process-test.js:55:19:55:22 | args | child_process-test.js:56:17:56:20 | args | | execSeries.js:3:20:3:22 | arr | execSeries.js:5:4:5:3 | arr | +| execSeries.js:3:20:3:22 | arr | execSeries.js:6:14:6:16 | arr | | execSeries.js:5:4:5:3 | arr | execSeries.js:6:14:6:16 | arr | | execSeries.js:6:14:6:16 | arr | execSeries.js:6:14:6:21 | arr[i++] | | execSeries.js:6:14:6:21 | arr[i++] | execSeries.js:14:24:14:30 | command | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected index c530d853079f..40c99b61fbb7 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected @@ -3,10 +3,7 @@ nodes | ReflectedXss.js:8:33:8:45 | req.params.id | | etherpad.js:9:5:9:53 | response | | etherpad.js:9:16:9:30 | req.query.jsonp | -| etherpad.js:9:16:9:36 | req.que ... p + "(" | -| etherpad.js:9:16:9:47 | req.que ... esponse | | etherpad.js:9:16:9:53 | req.que ... e + ")" | -| etherpad.js:11:3:11:3 | response | | etherpad.js:11:12:11:19 | response | | formatting.js:4:9:4:29 | evil | | formatting.js:4:16:4:29 | req.query.evil | @@ -45,8 +42,12 @@ nodes edges | ReflectedXss.js:8:33:8:45 | req.params.id | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | | etherpad.js:9:5:9:53 | response | etherpad.js:11:3:11:3 | response | +| etherpad.js:9:5:9:53 | response | etherpad.js:11:12:11:19 | response | | etherpad.js:9:16:9:30 | req.query.jsonp | etherpad.js:9:16:9:36 | req.que ... p + "(" | +| etherpad.js:9:16:9:30 | req.query.jsonp | etherpad.js:9:16:9:47 | req.que ... esponse | +| etherpad.js:9:16:9:30 | req.query.jsonp | etherpad.js:9:16:9:53 | req.que ... e + ")" | | etherpad.js:9:16:9:36 | req.que ... p + "(" | etherpad.js:9:16:9:47 | req.que ... esponse | +| etherpad.js:9:16:9:36 | req.que ... p + "(" | etherpad.js:9:16:9:53 | req.que ... e + ")" | | etherpad.js:9:16:9:47 | req.que ... esponse | etherpad.js:9:16:9:53 | req.que ... e + ")" | | etherpad.js:9:16:9:53 | req.que ... e + ")" | etherpad.js:9:5:9:53 | response | | etherpad.js:11:3:11:3 | response | etherpad.js:11:12:11:19 | response | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected index dd2fe4be6f61..415926a26f2f 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected @@ -6,7 +6,6 @@ nodes | jquery.js:2:17:2:33 | document.location | | jquery.js:2:17:2:40 | documen ... .search | | jquery.js:4:5:4:11 | tainted | -| jquery.js:7:5:7:26 | "