From 4cdaccd22e96f38822684451ed921d65f316c9b6 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 7 Aug 2024 14:03:25 +0200 Subject: [PATCH 01/37] JS: Add InlineFlowTest --- .../ql/test/testUtilities/InlineFlowTest.qll | 25 +++++++++++++++++++ .../test/testUtilities/InlineFlowTestUtil.qll | 21 ++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 javascript/ql/test/testUtilities/InlineFlowTest.qll create mode 100644 javascript/ql/test/testUtilities/InlineFlowTestUtil.qll diff --git a/javascript/ql/test/testUtilities/InlineFlowTest.qll b/javascript/ql/test/testUtilities/InlineFlowTest.qll new file mode 100644 index 000000000000..787f5f1540b5 --- /dev/null +++ b/javascript/ql/test/testUtilities/InlineFlowTest.qll @@ -0,0 +1,25 @@ +/** + * Inline flow tests for JavaScript. + * See `shared/util/codeql/dataflow/test/InlineFlowTest.qll` + */ + +private import javascript +private import semmle.javascript.Locations +private import codeql.dataflow.test.InlineFlowTest +private import semmle.javascript.dataflow.internal.sharedlib.DataFlowArg +private import semmle.javascript.frameworks.data.internal.ApiGraphModelsExtensions as ApiGraphModelsExtensions +private import internal.InlineExpectationsTestImpl + +private module FlowTestImpl implements InputSig { + import testUtilities.InlineFlowTestUtil + + bindingset[src, sink] + string getArgString(DataFlow::Node src, DataFlow::Node sink) { + (if exists(getSourceArgString(src)) then result = getSourceArgString(src) else result = "") and + exists(sink) + } + + predicate interpretModelForTest = ApiGraphModelsExtensions::interpretModelForTest/2; +} + +import InlineFlowTestMake diff --git a/javascript/ql/test/testUtilities/InlineFlowTestUtil.qll b/javascript/ql/test/testUtilities/InlineFlowTestUtil.qll new file mode 100644 index 000000000000..4072e4dd9e6b --- /dev/null +++ b/javascript/ql/test/testUtilities/InlineFlowTestUtil.qll @@ -0,0 +1,21 @@ +/** + * Defines the default source and sink recognition for `InlineFlowTest.qll`. + * + * We reuse these predicates in some type-tracking tests that don't wish to bring in the + * test configuration from `InlineFlowTest`. + */ + +private import javascript + +predicate defaultSource(DataFlow::Node src) { src.(DataFlow::CallNode).getCalleeName() = "source" } + +predicate defaultSink(DataFlow::Node sink) { + exists(DataFlow::CallNode call | call.getCalleeName() = "sink" | sink = call.getAnArgument()) +} + +bindingset[src] +string getSourceArgString(DataFlow::Node src) { + src.(DataFlow::CallNode).getAnArgument().getStringValue() = result + or + src.(DataFlow::ParameterNode).getName() = result +} From 5d77c336fcf7ee4ada7a3ee7865a9ad7f9dd5e5c Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 8 Aug 2024 20:04:11 +0200 Subject: [PATCH 02/37] Test case for spread and rest args/params --- .../library-tests/TripleDot/test.expected | 61 ++++++++++ .../ql/test/library-tests/TripleDot/test.ql | 3 + .../ql/test/library-tests/TripleDot/tst.js | 114 ++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 javascript/ql/test/library-tests/TripleDot/test.expected create mode 100644 javascript/ql/test/library-tests/TripleDot/test.ql create mode 100644 javascript/ql/test/library-tests/TripleDot/tst.js diff --git a/javascript/ql/test/library-tests/TripleDot/test.expected b/javascript/ql/test/library-tests/TripleDot/test.expected new file mode 100644 index 000000000000..046eb06471da --- /dev/null +++ b/javascript/ql/test/library-tests/TripleDot/test.expected @@ -0,0 +1,61 @@ +| tst.js:5:14:5:20 | rest[0] | Unexpected result: hasTaintFlow=t1.1 | +| tst.js:5:24:5:45 | // $ ha ... ow=t1.1 | Missing result:hasValueFlow=t1.1 | +| tst.js:6:14:6:20 | rest[1] | Unexpected result: hasTaintFlow=t1.1 | +| tst.js:6:24:6:45 | // $ ha ... ow=t1.2 | Missing result:hasValueFlow=t1.2 | +| tst.js:7:31:7:70 | // $ ha ... ow=t1.2 | Missing result:hasTaintFlow=t1.2 | +| tst.js:15:31:15:70 | // $ ha ... ow=t2.3 | Missing result:hasTaintFlow=t2.3 | +| tst.js:22:14:22:14 | x | Unexpected result: hasTaintFlow=t3.1 | +| tst.js:22:18:22:39 | // $ ha ... ow=t3.1 | Missing result:hasValueFlow=t3.1 | +| tst.js:23:14:23:14 | y | Unexpected result: hasTaintFlow=t3.1 | +| tst.js:23:18:23:39 | // $ ha ... ow=t3.2 | Missing result:hasValueFlow=t3.2 | +| tst.js:24:14:24:14 | z | Unexpected result: hasTaintFlow=t3.1 | +| tst.js:24:18:24:39 | // $ ha ... ow=t3.3 | Missing result:hasValueFlow=t3.3 | +| tst.js:34:14:34:14 | w | Unexpected result: hasTaintFlow=t4.1 | +| tst.js:35:14:35:14 | x | Unexpected result: hasTaintFlow=t4.1 | +| tst.js:35:18:35:39 | // $ ha ... ow=t4.1 | Missing result:hasValueFlow=t4.1 | +| tst.js:36:14:36:14 | y | Unexpected result: hasTaintFlow=t4.1 | +| tst.js:36:18:36:39 | // $ ha ... ow=t4.2 | Missing result:hasValueFlow=t4.2 | +| tst.js:37:14:37:14 | z | Unexpected result: hasTaintFlow=t4.1 | +| tst.js:37:18:37:39 | // $ ha ... ow=t4.3 | Missing result:hasValueFlow=t4.3 | +| tst.js:47:14:47:14 | w | Unexpected result: hasTaintFlow=t5.2 | +| tst.js:47:14:47:14 | w | Unexpected result: hasTaintFlow=t5.3 | +| tst.js:47:14:47:14 | w | Unexpected result: hasValueFlow=t5.1 | +| tst.js:48:14:48:14 | x | Unexpected result: hasTaintFlow=t5.1 | +| tst.js:48:14:48:14 | x | Unexpected result: hasTaintFlow=t5.3 | +| tst.js:48:14:48:14 | x | Unexpected result: hasValueFlow=t5.2 | +| tst.js:48:18:48:39 | // $ ha ... ow=t5.1 | Missing result:hasValueFlow=t5.1 | +| tst.js:49:14:49:14 | y | Unexpected result: hasTaintFlow=t5.1 | +| tst.js:49:14:49:14 | y | Unexpected result: hasTaintFlow=t5.2 | +| tst.js:49:14:49:14 | y | Unexpected result: hasValueFlow=t5.3 | +| tst.js:49:18:49:39 | // $ ha ... ow=t5.2 | Missing result:hasValueFlow=t5.2 | +| tst.js:50:14:50:14 | z | Unexpected result: hasTaintFlow=t5.1 | +| tst.js:50:14:50:14 | z | Unexpected result: hasTaintFlow=t5.2 | +| tst.js:50:14:50:14 | z | Unexpected result: hasTaintFlow=t5.3 | +| tst.js:50:18:50:39 | // $ ha ... ow=t5.3 | Missing result:hasValueFlow=t5.3 | +| tst.js:61:28:61:49 | // $ ha ... ow=t6.1 | Missing result:hasValueFlow=t6.1 | +| tst.js:62:28:62:49 | // $ ha ... ow=t6.2 | Missing result:hasValueFlow=t6.2 | +| tst.js:63:28:63:49 | // $ ha ... ow=t6.3 | Missing result:hasValueFlow=t6.3 | +| tst.js:70:18:70:39 | // $ ha ... ow=t7.1 | Missing result:hasValueFlow=t7.1 | +| tst.js:71:18:71:39 | // $ ha ... ow=t7.2 | Missing result:hasValueFlow=t7.2 | +| tst.js:72:18:72:39 | // $ ha ... ow=t7.3 | Missing result:hasValueFlow=t7.3 | +| tst.js:82:14:82:14 | x | Unexpected result: hasTaintFlow=t8.2 | +| tst.js:82:14:82:14 | x | Unexpected result: hasTaintFlow=t8.4 | +| tst.js:83:14:83:14 | y | Unexpected result: hasTaintFlow=t8.1 | +| tst.js:83:14:83:14 | y | Unexpected result: hasTaintFlow=t8.3 | +| tst.js:83:18:83:85 | // $ ha ... ow=t8.4 | Fixed spurious result:hasValueFlow=t8.3 | +| tst.js:84:14:84:14 | z | Unexpected result: hasTaintFlow=t8.1 | +| tst.js:84:14:84:14 | z | Unexpected result: hasTaintFlow=t8.2 | +| tst.js:84:14:84:14 | z | Unexpected result: hasTaintFlow=t8.3 | +| tst.js:84:14:84:14 | z | Unexpected result: hasTaintFlow=t8.4 | +| tst.js:84:18:84:85 | // $ ha ... ow=t8.4 | Fixed spurious result:hasValueFlow=t8.3 | +| tst.js:84:18:84:85 | // $ ha ... ow=t8.4 | Fixed spurious result:hasValueFlow=t8.4 | +| tst.js:84:18:84:85 | // $ ha ... ow=t8.4 | Missing result:hasValueFlow=t8.3 | +| tst.js:94:18:94:39 | // $ ha ... ow=t9.1 | Missing result:hasValueFlow=t9.1 | +| tst.js:95:18:95:39 | // $ ha ... ow=t9.2 | Missing result:hasValueFlow=t9.2 | +| tst.js:96:18:96:39 | // $ ha ... ow=t9.3 | Missing result:hasValueFlow=t9.3 | +| tst.js:106:14:106:14 | x | Unexpected result: hasTaintFlow=t10.1 | +| tst.js:106:18:106:40 | // $ ha ... w=t10.1 | Missing result:hasValueFlow=t10.1 | +| tst.js:107:14:107:14 | y | Unexpected result: hasTaintFlow=t10.1 | +| tst.js:107:18:107:40 | // $ ha ... w=t10.2 | Missing result:hasValueFlow=t10.2 | +| tst.js:108:14:108:14 | z | Unexpected result: hasTaintFlow=t10.1 | +| tst.js:108:18:108:40 | // $ ha ... w=t10.3 | Missing result:hasValueFlow=t10.3 | diff --git a/javascript/ql/test/library-tests/TripleDot/test.ql b/javascript/ql/test/library-tests/TripleDot/test.ql new file mode 100644 index 000000000000..222c24dbbea5 --- /dev/null +++ b/javascript/ql/test/library-tests/TripleDot/test.ql @@ -0,0 +1,3 @@ +import javascript +import testUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/javascript/ql/test/library-tests/TripleDot/tst.js b/javascript/ql/test/library-tests/TripleDot/tst.js new file mode 100644 index 000000000000..3613857d455c --- /dev/null +++ b/javascript/ql/test/library-tests/TripleDot/tst.js @@ -0,0 +1,114 @@ +import 'dummy'; + +function t1() { + function target(...rest) { + sink(rest[0]); // $ hasValueFlow=t1.1 + sink(rest[1]); // $ hasValueFlow=t1.2 + sink(rest.join(',')); // $ hasTaintFlow=t1.1 hasTaintFlow=t1.2 + } + target(source('t1.1'), source('t1.2')); +} + +function t2() { + function target(x, ...rest) { + sink(x); // $ hasValueFlow=t2.1 + sink(rest.join(',')); // $ hasTaintFlow=t2.2 hasTaintFlow=t2.3 + } + target(source('t2.1'), source('t2.2'), source('t2.3')); +} + +function t3() { + function finalTarget(x, y, z) { + sink(x); // $ hasValueFlow=t3.1 + sink(y); // $ hasValueFlow=t3.2 + sink(z); // $ hasValueFlow=t3.3 + } + function target(...rest) { + finalTarget(...rest); + } + target(source('t3.1'), source('t3.2'), source('t3.3')); +} + +function t4() { + function finalTarget(w, x, y, z) { + sink(w); // $ hasValueFlow=t4.0 + sink(x); // $ hasValueFlow=t4.1 + sink(y); // $ hasValueFlow=t4.2 + sink(z); // $ hasValueFlow=t4.3 + } + function target(...rest) { + finalTarget(source('t4.0'), ...rest); + } + target(source('t4.1'), source('t4.2'), source('t4.3')); +} + +function t5() { + function finalTarget(w, x, y, z) { + sink(w); // $ hasValueFlow=t5.0 + sink(x); // $ hasValueFlow=t5.1 + sink(y); // $ hasValueFlow=t5.2 + sink(z); // $ hasValueFlow=t5.3 + } + function target(array) { + finalTarget(source('t5.0'), ...array); + } + target([source('t5.1'), source('t5.2'), source('t5.3')]); +} + +function t6() { + function target(x) { + sink(x); // $ hasValueFlow=t6.1 + sink(arguments[0]);// $ hasValueFlow=t6.1 + sink(arguments[1]);// $ hasValueFlow=t6.2 + sink(arguments[2]);// $ hasValueFlow=t6.3 + } + target(source('t6.1'), source('t6.2'), source('t6.3')); +} + +function t7() { + function finalTarget(x, y, z) { + sink(x); // $ hasValueFlow=t7.1 + sink(y); // $ hasValueFlow=t7.2 + sink(z); // $ hasValueFlow=t7.3 + } + function target() { + finalTarget(...arguments); + } + target(source('t7.1'), source('t7.2'), source('t7.3')); +} + +function t8() { + function finalTarget(x, y, z) { + sink(x); // $ hasValueFlow=t8.1 SPURIOUS: hasValueFlow=t8.3 + sink(y); // $ hasValueFlow=t8.2 SPURIOUS: hasValueFlow=t8.3 hasValueFlow=t8.4 + sink(z); // $ hasValueFlow=t8.3 SPURIOUS: hasValueFlow=t8.3 hasValueFlow=t8.4 + } + function target(array1, array2) { + finalTarget(...array1, ...array2); + } + target([source('t8.1'), source('t8.2')], [source('t8.3'), source('t8.4')]); +} + +function t9() { + function finalTarget(x, y, z) { + sink(x); // $ hasValueFlow=t9.1 + sink(y); // $ hasValueFlow=t9.2 + sink(z); // $ hasValueFlow=t9.3 + } + function target() { + finalTarget.apply(undefined, arguments); + } + target(source('t9.1'), source('t9.2'), source('t9.3')); +} + +function t10() { + function finalTarget(x, y, z) { + sink(x); // $ hasValueFlow=t10.1 + sink(y); // $ hasValueFlow=t10.2 + sink(z); // $ hasValueFlow=t10.3 + } + function target(...rest) { + finalTarget.apply(undefined, rest); + } + target(source('t10.1'), source('t10.2'), source('t10.3')); +} From 6c7d745a2bc774744c0cde31b5dfa49c36e9fc90 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 9 Aug 2024 10:08:45 +0200 Subject: [PATCH 03/37] JS: Add nodes for static/dynamic argument/parameter arrays --- .../dataflow/internal/DataFlowNode.qll | 6 ++ .../dataflow/internal/DataFlowPrivate.qll | 67 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll index 4e10b6b27e19..2499e92b7db3 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll @@ -33,6 +33,12 @@ private module Cached { } or TThisNode(StmtContainer f) { f.(Function).getThisBinder() = f or f instanceof TopLevel } or TFunctionSelfReferenceNode(Function f) or + TStaticArgumentArrayNode(InvokeExpr node) or + TDynamicArgumentArrayNode(InvokeExpr node) { node.isSpreadArgument(_) } or + TStaticParameterArrayNode(Function f) { + f.getAParameter().isRestParameter() or f.usesArgumentsObject() + } or + TDynamicParameterArrayNode(Function f) or TDestructuredModuleImportNode(ImportDeclaration decl) { exists(decl.getASpecifier().getImportedName()) } or diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll index 8f9e3ee6f6fb..ac508e0e9e74 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll @@ -81,6 +81,73 @@ class GenericSynthesizedNode extends DataFlow::Node, TGenericSynthesizedNode { string getTag() { result = tag } } +/** + * An argument containing an array of all positional arguments with an obvious index, i.e. not affected by a spread argument. + */ +class StaticArgumentArrayNode extends DataFlow::Node, TStaticArgumentArrayNode { + private InvokeExpr invoke; + + StaticArgumentArrayNode() { this = TStaticArgumentArrayNode(invoke) } + + override StmtContainer getContainer() { result = invoke.getContainer() } + + override string toString() { result = "[static argument array]" } + + override Location getLocation() { result = invoke.getLocation() } +} + +/** + * An argument containing an array of all positional arguments with non-obvious index, i.e. affected by a spread argument. + * + * Only exists for call sites with a spread argument. + */ +class DynamicArgumentArrayNode extends DataFlow::Node, TDynamicArgumentArrayNode { + private InvokeExpr invoke; + + DynamicArgumentArrayNode() { this = TDynamicArgumentArrayNode(invoke) } + + override StmtContainer getContainer() { result = invoke.getContainer() } + + override string toString() { result = "[dynamic argument array]" } + + override Location getLocation() { result = invoke.getLocation() } +} + +/** + * A parameter containing an array of all positional arguments with an obvious index, i.e. not affected by spread or `.apply()`. + * + * These are read and stored in the function's rest parameter and `arguments` array. + * The node only exists for functions with a rest parameter or which uses the `arguments` array. + */ +class StaticParameterArrayNode extends DataFlow::Node, TStaticParameterArrayNode { + private Function function; + + StaticParameterArrayNode() { this = TStaticParameterArrayNode(function) } + + override StmtContainer getContainer() { result = function } + + override string toString() { result = "[static parameter array]" } + + override Location getLocation() { result = function.getLocation() } +} + +/** + * A parameter containing an array of all positional argument values with non-obvious index, i.e. affected by spread or `.apply()`. + * + * These are read and assigned into regular positional parameters and stored into rest parameters and the `arguments` array. + */ +class DynamicParameterArrayNode extends DataFlow::Node, TDynamicParameterArrayNode { + private Function function; + + DynamicParameterArrayNode() { this = TDynamicParameterArrayNode(function) } + + override StmtContainer getContainer() { result = function } + + override string toString() { result = "[dynamic parameter array]" } + + override Location getLocation() { result = function.getLocation() } +} + cached newtype TReturnKind = MkNormalReturnKind() or From a72f79576a1527d1e42bd738a9fd1409f76a970e Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 9 Aug 2024 10:24:02 +0200 Subject: [PATCH 04/37] JS: Add corresponding argument positions --- .../dataflow/internal/DataFlowPrivate.qll | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll index ac508e0e9e74..d25c53cb786a 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll @@ -293,7 +293,11 @@ private predicate isParameterNodeImpl(Node p, DataFlowCallable c, ParameterPosit or pos.isFunctionSelfReference() and p = TFunctionSelfReferenceNode(c.asSourceCallable()) or - pos.isArgumentsArray() and p = TReflectiveParametersNode(c.asSourceCallable()) + pos.isArgumentsArray() and p = TReflectiveParametersNode(c.asSourceCallable()) // TODO: remove + or + pos.isStaticArgumentArray() and p = TStaticParameterArrayNode(c.asSourceCallable()) + or + pos.isDynamicArgumentArray() and p = TDynamicParameterArrayNode(c.asSourceCallable()) or exists(FlowSummaryNode summaryNode | summaryNode = p and @@ -347,6 +351,14 @@ private predicate isArgumentNodeImpl(Node n, DataFlowCall call, ArgumentPosition or FlowSummaryImpl::Private::summaryArgumentNode(call.(SummaryCall).getReceiver(), n.(FlowSummaryNode).getSummaryNode(), pos) + or + exists(InvokeExpr invoke | call.asOrdinaryCall() = TValueNode(invoke) | + n = TStaticArgumentArrayNode(invoke) and + pos.isStaticArgumentArray() + or + n = TDynamicArgumentArrayNode(invoke) and + pos.isDynamicArgumentArray() + ) } predicate isArgumentNode(ArgumentNode n, DataFlowCall call, ArgumentPosition pos) { @@ -738,7 +750,9 @@ newtype TParameterPosition = MkPositionalLowerBound(int n) { n = [0 .. getMaxArity()] } or MkThisParameter() or MkFunctionSelfReferenceParameter() or - MkArgumentsArrayParameter() + MkArgumentsArrayParameter() or // TODO: remove + MkStaticArgumentArray() or + MkDynamicArgumentArray() class ParameterPosition extends TParameterPosition { predicate isPositionalExact() { this instanceof MkPositionalParameter } @@ -755,7 +769,11 @@ class ParameterPosition extends TParameterPosition { predicate isFunctionSelfReference() { this = MkFunctionSelfReferenceParameter() } - predicate isArgumentsArray() { this = MkArgumentsArrayParameter() } + predicate isArgumentsArray() { this = MkArgumentsArrayParameter() } // TODO: remove + + predicate isStaticArgumentArray() { this = MkStaticArgumentArray() } + + predicate isDynamicArgumentArray() { this = MkDynamicArgumentArray() } string toString() { result = this.asPositional().toString() @@ -766,7 +784,11 @@ class ParameterPosition extends TParameterPosition { or this.isFunctionSelfReference() and result = "function" or - this.isArgumentsArray() and result = "arguments-array" + this = MkArgumentsArrayParameter() and result = "deprecated-arguments-array" + or + this.isStaticArgumentArray() and result = "static-argument-array" + or + this.isDynamicArgumentArray() and result = "dynamic-argument-array" } } From 623dbda77ddd4a092bb3c8beedcfb0001fc4c7a2 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 12 Aug 2024 13:18:58 +0200 Subject: [PATCH 05/37] Do not pass regular positional args into the rest parameter --- .../semmle/javascript/dataflow/internal/DataFlowPrivate.qll | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll index d25c53cb786a..1b08b63f8975 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll @@ -287,7 +287,11 @@ abstract class LibraryCallable extends string { } private predicate isParameterNodeImpl(Node p, DataFlowCallable c, ParameterPosition pos) { - p = c.asSourceCallable().(Function).getParameter(pos.asPositional()).flow() + exists(Parameter parameter | + parameter = c.asSourceCallable().(Function).getParameter(pos.asPositional()) and + not parameter.isRestParameter() and + p = TValueNode(parameter) + ) or pos.isThis() and p = TThisNode(c.asSourceCallable().(Function)) or From fa7ad0306848966ba61d9de90c089f02e8a4ea98 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 9 Aug 2024 11:17:35 +0200 Subject: [PATCH 06/37] JS: Add store/load steps for the new argument arrays --- .../semmle/javascript/dataflow/DataFlow.qll | 5 +- .../dataflow/internal/DataFlowNode.qll | 18 ++- .../dataflow/internal/DataFlowPrivate.qll | 144 +++++++++++++++++- .../library-tests/TripleDot/test.expected | 61 -------- .../ql/test/library-tests/TripleDot/tst.js | 2 +- 5 files changed, 158 insertions(+), 72 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll index a80b2e79ff9c..433cf286c343 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll @@ -1780,8 +1780,7 @@ module DataFlow { ) } - /** A load step from a reflective parameter node to each parameter. */ - private class ReflectiveParamsStep extends PreCallGraphStep { + private class ReflectiveParamsStep extends LegacyPreCallGraphStep { override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) { exists(DataFlow::ReflectiveParametersNode params, DataFlow::FunctionNode f, int i | f.getFunction() = params.getFunction() and @@ -1793,7 +1792,7 @@ module DataFlow { } /** A taint step from the reflective parameters node to any parameter. */ - private class ReflectiveParamsTaintStep extends TaintTracking::SharedTaintStep { + private class ReflectiveParamsTaintStep extends TaintTracking::LegacyTaintStep { override predicate step(DataFlow::Node obj, DataFlow::Node element) { exists(DataFlow::ReflectiveParametersNode params, DataFlow::FunctionNode f | f.getFunction() = params.getFunction() and diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll index 2499e92b7db3..ab152e34f9d4 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll @@ -15,6 +15,12 @@ private import semmle.javascript.dataflow.internal.VariableCapture as VariableCa cached private module Cached { + private Content dynamicArgumentsContent() { + result.asArrayIndex() = [0 .. 10] + or + result.isUnknownArrayElement() + } + /** * The raw data type underlying `DataFlow::Node`. */ @@ -39,6 +45,16 @@ private module Cached { f.getAParameter().isRestParameter() or f.usesArgumentsObject() } or TDynamicParameterArrayNode(Function f) or + /** Data about to be stored in the rest parameter object. Needed for shifting array indices. */ + TRestParameterStoreNode(Function f, Content storeContent) { + f.getRestParameter().getIndex() > 0 and + storeContent = dynamicArgumentsContent() + } or + /** Data about to be stored in the dynamic argument array of an invocation. Needed for shifting array indices. */ + TDynamicArgumentStoreNode(InvokeExpr invoke, Content storeContent) { + invoke.isSpreadArgument(_) and + storeContent = dynamicArgumentsContent() + } or TDestructuredModuleImportNode(ImportDeclaration decl) { exists(decl.getASpecifier().getImportedName()) } or @@ -49,7 +65,7 @@ private module Cached { TExceptionalInvocationReturnNode(InvokeExpr e) or TGlobalAccessPathRoot() or TTemplatePlaceholderTag(Templating::TemplatePlaceholderTag tag) or - TReflectiveParametersNode(Function f) or + TReflectiveParametersNode(Function f) { f.usesArgumentsObject() } or TExprPostUpdateNode(AST::ValueNode e) { e = any(InvokeExpr invoke).getAnArgument() or e = any(PropAccess access).getBase() or diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll index 1b08b63f8975..c4b1ee8d6eac 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll @@ -113,6 +113,42 @@ class DynamicArgumentArrayNode extends DataFlow::Node, TDynamicArgumentArrayNode override Location getLocation() { result = invoke.getLocation() } } +/** + * Intermediate node with data that will be stored in `DyanmicArgumentArrayNode`. + */ +class DynamicArgumentStoreNode extends DataFlow::Node, TDynamicArgumentStoreNode { + private InvokeExpr invoke; + private Content content; + + DynamicArgumentStoreNode() { this = TDynamicArgumentStoreNode(invoke, content) } + + override StmtContainer getContainer() { result = invoke.getContainer() } + + override string toString() { result = "[dynamic argument store node] content=" + content } + + override Location getLocation() { result = invoke.getLocation() } +} + +/** + * Intermediate node with data that will be stored in the function's rest parameter node. + */ +class RestParameterStoreNode extends DataFlow::Node, TRestParameterStoreNode { + private Function function; + private Content content; + + RestParameterStoreNode() { this = TRestParameterStoreNode(function, content) } + + override StmtContainer getContainer() { result = function } + + override string toString() { + result = + "[rest parameter store node] '..." + function.getRestParameter().getName() + "' content=" + + content + } + + override Location getLocation() { result = function.getRestParameter().getLocation() } +} + /** * A parameter containing an array of all positional arguments with an obvious index, i.e. not affected by spread or `.apply()`. * @@ -297,8 +333,6 @@ private predicate isParameterNodeImpl(Node p, DataFlowCallable c, ParameterPosit or pos.isFunctionSelfReference() and p = TFunctionSelfReferenceNode(c.asSourceCallable()) or - pos.isArgumentsArray() and p = TReflectiveParametersNode(c.asSourceCallable()) // TODO: remove - or pos.isStaticArgumentArray() and p = TStaticParameterArrayNode(c.asSourceCallable()) or pos.isDynamicArgumentArray() and p = TDynamicParameterArrayNode(c.asSourceCallable()) @@ -317,6 +351,12 @@ predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition private predicate isArgumentNodeImpl(Node n, DataFlowCall call, ArgumentPosition pos) { n = call.asOrdinaryCall().getArgument(pos.asPositional()) or + exists(InvokeExpr invoke | + call.asOrdinaryCall() = TReflectiveCallNode(invoke, "apply") and + pos.isDynamicArgumentArray() and + n = TValueNode(invoke.getArgument(1)) + ) + or pos.isThis() and n = call.asOrdinaryCall().(DataFlow::CallNode).getReceiver() or exists(DataFlow::PartialInvokeNode invoke, DataFlow::Node callback | @@ -343,10 +383,6 @@ private predicate isArgumentNodeImpl(Node n, DataFlowCall call, ArgumentPosition or pos.isThis() and n = TConstructorThisArgumentNode(call.asOrdinaryCall().asExpr()) or - // For now, treat all spread argument as flowing into the 'arguments' array, regardless of preceding arguments - n = call.asOrdinaryCall().getASpreadArgument() and - pos.isArgumentsArray() - or // receiver of accessor call pos.isThis() and n = call.asAccessorCall().getBase() or @@ -953,6 +989,39 @@ predicate simpleLocalFlowStep(Node node1, Node node2) { or // NOTE: For consistency with readStep/storeStep, we do not translate these steps to jump steps automatically. DataFlow::AdditionalFlowStep::step(node1, node2) + or + exists(InvokeExpr invoke | + // When the first argument is a spread argument, flow into the argument array as a local flow step + // to ensure we preserve knowledge about array indices + node1 = TValueNode(invoke.getArgument(0).stripParens().(SpreadElement).getOperand()) and + node2 = TDynamicArgumentArrayNode(invoke) + ) + or + exists(Function f | + // When the first parameter is a rest parameter, flow into the rest parameter as a local flow step + // to ensure we preserve knowledge about array indices + (node1 = TStaticParameterArrayNode(f) or node1 = TDynamicParameterArrayNode(f)) + | + // rest parameter at initial position + exists(Parameter rest | + rest = f.getParameter(0) and + rest.isRestParameter() and + node2 = TValueNode(rest) + ) + or + // 'arguments' array + node2 = TReflectiveParametersNode(f) + ) + or + // Prepare to store non-spread arguments after a spread into the dynamic arguments array + exists(InvokeExpr invoke, int n, Expr argument, Content storeContent | + invoke.getArgument(n) = argument and + not argument instanceof SpreadElement and + n > firstSpreadArgumentIndex(invoke) and + node1 = TValueNode(argument) and + node2 = TDynamicArgumentStoreNode(invoke, storeContent) and + storeContent.isUnknownArrayElement() + ) } predicate localMustFlowStep(Node node1, Node node2) { node1 = node2.getImmediatePredecessor() } @@ -1018,6 +1087,42 @@ predicate readStep(Node node1, ContentSet c, Node node2) { ) or DataFlow::AdditionalFlowStep::readStep(node1, c, node2) + or + // Pass dynamic arguments into plain parameters + exists(Function function, Parameter param, int n | + param = function.getParameter(n) and + not param.isRestParameter() and + node1 = TDynamicParameterArrayNode(function) and + node2 = TValueNode(param) and + c = ContentSet::arrayElementFromInt(n) + ) + or + // Prepare to store dynamic and static arguments into the rest parameter array when it isn't the first parameter + exists(Function function, Content content, int restIndex | + restIndex = function.getRestParameter().getIndex() and + restIndex > 0 and + (node1 = TStaticParameterArrayNode(function) or node1 = TDynamicParameterArrayNode(function)) and + node2 = TRestParameterStoreNode(function, content) + | + // shift known array indices + c.asArrayIndex() = content.asArrayIndex() + restIndex + or + content.isUnknownArrayElement() and // TODO: don't read unknown array elements from static array + c = ContentSet::arrayElementUnknown() + ) + or + // Prepare to store spread arguments into the dynamic arguments array, when it isn't the initial spread argument + exists(InvokeExpr invoke, int n, Expr argument, Content storeContent | + invoke.getArgument(n).stripParens().(SpreadElement).getOperand() = argument and + n > 0 and // n=0 is handled as a value step + node1 = TValueNode(argument) and + node2 = TDynamicArgumentStoreNode(invoke, storeContent) and + if n > firstSpreadArgumentIndex(invoke) + then + c = ContentSet::arrayElement() and // unknown start index when not the first spread operator + storeContent.isUnknownArrayElement() + else storeContent.asArrayIndex() = n + c.asArrayIndex() + ) } /** Gets the post-update node for which `node` is the corresponding pre-update node. */ @@ -1032,6 +1137,11 @@ private Node tryGetPostUpdate(Node node) { result = node } +pragma[nomagic] +private int firstSpreadArgumentIndex(InvokeExpr expr) { + result = min(int i | expr.isSpreadArgument(i)) +} + /** * Holds if data can flow from `node1` to `node2` via a store into `c`. Thus, * `node2` references an object with a content `c.getAStoreContent()` that @@ -1063,6 +1173,25 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { ) or DataFlow::AdditionalFlowStep::storeStep(node1, c, node2) + or + exists(Function f, Content storeContent | + node1 = TRestParameterStoreNode(f, storeContent) and + node2 = TValueNode(f.getRestParameter()) and + c.asSingleton() = storeContent + ) + or + exists(InvokeExpr invoke, Content storeContent | + node1 = TDynamicArgumentStoreNode(invoke, storeContent) and + node2 = TDynamicArgumentArrayNode(invoke) and + c.asSingleton() = storeContent + ) + or + exists(InvokeExpr invoke, int n | + node1 = TValueNode(invoke.getArgument(n)) and + node2 = TStaticArgumentArrayNode(invoke) and + c.asArrayIndex() = n and + not n >= firstSpreadArgumentIndex(invoke) + ) } /** @@ -1112,6 +1241,9 @@ predicate expectsContent(Node n, ContentSet c) { c = MkPromiseFilter() or any(AdditionalFlowInternal flow).expectsContent(n, c) + or + c = ContentSet::arrayElement() and + n instanceof TDynamicParameterArrayNode } abstract class NodeRegion extends Unit { diff --git a/javascript/ql/test/library-tests/TripleDot/test.expected b/javascript/ql/test/library-tests/TripleDot/test.expected index 046eb06471da..e69de29bb2d1 100644 --- a/javascript/ql/test/library-tests/TripleDot/test.expected +++ b/javascript/ql/test/library-tests/TripleDot/test.expected @@ -1,61 +0,0 @@ -| tst.js:5:14:5:20 | rest[0] | Unexpected result: hasTaintFlow=t1.1 | -| tst.js:5:24:5:45 | // $ ha ... ow=t1.1 | Missing result:hasValueFlow=t1.1 | -| tst.js:6:14:6:20 | rest[1] | Unexpected result: hasTaintFlow=t1.1 | -| tst.js:6:24:6:45 | // $ ha ... ow=t1.2 | Missing result:hasValueFlow=t1.2 | -| tst.js:7:31:7:70 | // $ ha ... ow=t1.2 | Missing result:hasTaintFlow=t1.2 | -| tst.js:15:31:15:70 | // $ ha ... ow=t2.3 | Missing result:hasTaintFlow=t2.3 | -| tst.js:22:14:22:14 | x | Unexpected result: hasTaintFlow=t3.1 | -| tst.js:22:18:22:39 | // $ ha ... ow=t3.1 | Missing result:hasValueFlow=t3.1 | -| tst.js:23:14:23:14 | y | Unexpected result: hasTaintFlow=t3.1 | -| tst.js:23:18:23:39 | // $ ha ... ow=t3.2 | Missing result:hasValueFlow=t3.2 | -| tst.js:24:14:24:14 | z | Unexpected result: hasTaintFlow=t3.1 | -| tst.js:24:18:24:39 | // $ ha ... ow=t3.3 | Missing result:hasValueFlow=t3.3 | -| tst.js:34:14:34:14 | w | Unexpected result: hasTaintFlow=t4.1 | -| tst.js:35:14:35:14 | x | Unexpected result: hasTaintFlow=t4.1 | -| tst.js:35:18:35:39 | // $ ha ... ow=t4.1 | Missing result:hasValueFlow=t4.1 | -| tst.js:36:14:36:14 | y | Unexpected result: hasTaintFlow=t4.1 | -| tst.js:36:18:36:39 | // $ ha ... ow=t4.2 | Missing result:hasValueFlow=t4.2 | -| tst.js:37:14:37:14 | z | Unexpected result: hasTaintFlow=t4.1 | -| tst.js:37:18:37:39 | // $ ha ... ow=t4.3 | Missing result:hasValueFlow=t4.3 | -| tst.js:47:14:47:14 | w | Unexpected result: hasTaintFlow=t5.2 | -| tst.js:47:14:47:14 | w | Unexpected result: hasTaintFlow=t5.3 | -| tst.js:47:14:47:14 | w | Unexpected result: hasValueFlow=t5.1 | -| tst.js:48:14:48:14 | x | Unexpected result: hasTaintFlow=t5.1 | -| tst.js:48:14:48:14 | x | Unexpected result: hasTaintFlow=t5.3 | -| tst.js:48:14:48:14 | x | Unexpected result: hasValueFlow=t5.2 | -| tst.js:48:18:48:39 | // $ ha ... ow=t5.1 | Missing result:hasValueFlow=t5.1 | -| tst.js:49:14:49:14 | y | Unexpected result: hasTaintFlow=t5.1 | -| tst.js:49:14:49:14 | y | Unexpected result: hasTaintFlow=t5.2 | -| tst.js:49:14:49:14 | y | Unexpected result: hasValueFlow=t5.3 | -| tst.js:49:18:49:39 | // $ ha ... ow=t5.2 | Missing result:hasValueFlow=t5.2 | -| tst.js:50:14:50:14 | z | Unexpected result: hasTaintFlow=t5.1 | -| tst.js:50:14:50:14 | z | Unexpected result: hasTaintFlow=t5.2 | -| tst.js:50:14:50:14 | z | Unexpected result: hasTaintFlow=t5.3 | -| tst.js:50:18:50:39 | // $ ha ... ow=t5.3 | Missing result:hasValueFlow=t5.3 | -| tst.js:61:28:61:49 | // $ ha ... ow=t6.1 | Missing result:hasValueFlow=t6.1 | -| tst.js:62:28:62:49 | // $ ha ... ow=t6.2 | Missing result:hasValueFlow=t6.2 | -| tst.js:63:28:63:49 | // $ ha ... ow=t6.3 | Missing result:hasValueFlow=t6.3 | -| tst.js:70:18:70:39 | // $ ha ... ow=t7.1 | Missing result:hasValueFlow=t7.1 | -| tst.js:71:18:71:39 | // $ ha ... ow=t7.2 | Missing result:hasValueFlow=t7.2 | -| tst.js:72:18:72:39 | // $ ha ... ow=t7.3 | Missing result:hasValueFlow=t7.3 | -| tst.js:82:14:82:14 | x | Unexpected result: hasTaintFlow=t8.2 | -| tst.js:82:14:82:14 | x | Unexpected result: hasTaintFlow=t8.4 | -| tst.js:83:14:83:14 | y | Unexpected result: hasTaintFlow=t8.1 | -| tst.js:83:14:83:14 | y | Unexpected result: hasTaintFlow=t8.3 | -| tst.js:83:18:83:85 | // $ ha ... ow=t8.4 | Fixed spurious result:hasValueFlow=t8.3 | -| tst.js:84:14:84:14 | z | Unexpected result: hasTaintFlow=t8.1 | -| tst.js:84:14:84:14 | z | Unexpected result: hasTaintFlow=t8.2 | -| tst.js:84:14:84:14 | z | Unexpected result: hasTaintFlow=t8.3 | -| tst.js:84:14:84:14 | z | Unexpected result: hasTaintFlow=t8.4 | -| tst.js:84:18:84:85 | // $ ha ... ow=t8.4 | Fixed spurious result:hasValueFlow=t8.3 | -| tst.js:84:18:84:85 | // $ ha ... ow=t8.4 | Fixed spurious result:hasValueFlow=t8.4 | -| tst.js:84:18:84:85 | // $ ha ... ow=t8.4 | Missing result:hasValueFlow=t8.3 | -| tst.js:94:18:94:39 | // $ ha ... ow=t9.1 | Missing result:hasValueFlow=t9.1 | -| tst.js:95:18:95:39 | // $ ha ... ow=t9.2 | Missing result:hasValueFlow=t9.2 | -| tst.js:96:18:96:39 | // $ ha ... ow=t9.3 | Missing result:hasValueFlow=t9.3 | -| tst.js:106:14:106:14 | x | Unexpected result: hasTaintFlow=t10.1 | -| tst.js:106:18:106:40 | // $ ha ... w=t10.1 | Missing result:hasValueFlow=t10.1 | -| tst.js:107:14:107:14 | y | Unexpected result: hasTaintFlow=t10.1 | -| tst.js:107:18:107:40 | // $ ha ... w=t10.2 | Missing result:hasValueFlow=t10.2 | -| tst.js:108:14:108:14 | z | Unexpected result: hasTaintFlow=t10.1 | -| tst.js:108:18:108:40 | // $ ha ... w=t10.3 | Missing result:hasValueFlow=t10.3 | diff --git a/javascript/ql/test/library-tests/TripleDot/tst.js b/javascript/ql/test/library-tests/TripleDot/tst.js index 3613857d455c..3206ad657d00 100644 --- a/javascript/ql/test/library-tests/TripleDot/tst.js +++ b/javascript/ql/test/library-tests/TripleDot/tst.js @@ -79,7 +79,7 @@ function t7() { function t8() { function finalTarget(x, y, z) { - sink(x); // $ hasValueFlow=t8.1 SPURIOUS: hasValueFlow=t8.3 + sink(x); // $ hasValueFlow=t8.1 SPURIOUS: hasValueFlow=t8.3 hasValueFlow=t8.4 sink(y); // $ hasValueFlow=t8.2 SPURIOUS: hasValueFlow=t8.3 hasValueFlow=t8.4 sink(z); // $ hasValueFlow=t8.3 SPURIOUS: hasValueFlow=t8.3 hasValueFlow=t8.4 } From ed33a6e91bda710a2687a8d1bd6b6fe91bc0ffc0 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 12 Aug 2024 13:14:18 +0200 Subject: [PATCH 07/37] JS: Add explicit model of .join() --- .../internal/flow_summaries/Arrays.qll | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll index 054e617721e2..8ab74e217b10 100644 --- a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll +++ b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll @@ -1,7 +1,7 @@ /** - * Contains a summary for relevant methods on arrays, except Array.prototype.join which is currently special-cased in StringConcatenation.qll. + * Contains a summary for relevant methods on arrays. * - * Note that some of Array methods are modelled in `AmbiguousCoreMethods.qll`, and `join` and `toString` are special-cased elsewhere. + * Note that some of Array methods are modelled in `AmbiguousCoreMethods.qll`, and `toString` is special-cased elsewhere. */ private import javascript @@ -116,6 +116,26 @@ class ArrayConstructorSummary extends SummarizedCallable { } } +/** + * A call to `join` with a separator argument. + * + * Calls without separators are modelled in `StringConcatenation.qll`. + */ +class Join extends SummarizedCallable { + Join() { this = "Array#join" } + + override InstanceCall getACallSimple() { + result.getMethodName() = "join" and + result.getNumArgument() = [0, 1] + } + + override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + preservesValue = false and + input = "Argument[this].ArrayElement" and + output = "ReturnValue" + } +} + class CopyWithin extends SummarizedCallable { CopyWithin() { this = "Array#copyWithin" } From bbb1c8c374c1b6a35ad5401f44809178aa9951f0 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 12 Aug 2024 13:58:42 +0200 Subject: [PATCH 08/37] Remove old arguments-array position --- .../semmle/javascript/dataflow/internal/DataFlowPrivate.qll | 5 ----- .../javascript/dataflow/internal/FlowSummaryPrivate.qll | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll index c4b1ee8d6eac..99929776e71a 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll @@ -790,7 +790,6 @@ newtype TParameterPosition = MkPositionalLowerBound(int n) { n = [0 .. getMaxArity()] } or MkThisParameter() or MkFunctionSelfReferenceParameter() or - MkArgumentsArrayParameter() or // TODO: remove MkStaticArgumentArray() or MkDynamicArgumentArray() @@ -809,8 +808,6 @@ class ParameterPosition extends TParameterPosition { predicate isFunctionSelfReference() { this = MkFunctionSelfReferenceParameter() } - predicate isArgumentsArray() { this = MkArgumentsArrayParameter() } // TODO: remove - predicate isStaticArgumentArray() { this = MkStaticArgumentArray() } predicate isDynamicArgumentArray() { this = MkDynamicArgumentArray() } @@ -824,8 +821,6 @@ class ParameterPosition extends TParameterPosition { or this.isFunctionSelfReference() and result = "function" or - this = MkArgumentsArrayParameter() and result = "deprecated-arguments-array" - or this.isStaticArgumentArray() and result = "static-argument-array" or this.isDynamicArgumentArray() and result = "dynamic-argument-array" diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll index d978f81fb8a1..ca38d30e9013 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll @@ -35,7 +35,7 @@ private predicate positionName(ParameterPosition pos, string operand) { or pos.isFunctionSelfReference() and operand = "function" or - pos.isArgumentsArray() and operand = "arguments-array" + pos.isDynamicArgumentArray() and operand = "arguments-array" // TODO: remove and handle automatically or operand = pos.asPositionalLowerBound() + ".." } From 60c3d077b2fe813c07d36fcd27b032b57657a38e Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 12 Aug 2024 14:08:07 +0200 Subject: [PATCH 09/37] Update DataFlowImplConsistency.qll --- .../dataflow/internal/DataFlowImplConsistency.qll | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowImplConsistency.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowImplConsistency.qll index 84f0f3e39b4f..5b166b891190 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowImplConsistency.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowImplConsistency.qll @@ -37,6 +37,12 @@ private module ConsistencyConfig implements InputSig { isAmbientNode(call.asOrdinaryCall()) or isAmbientNode(call.asAccessorCall()) } + + predicate argHasPostUpdateExclude(ArgumentNode node) { + // Side-effects directly on these can't propagate back to the caller, and for longer access paths it's too imprecise + node instanceof TStaticArgumentArrayNode or + node instanceof TDynamicArgumentArrayNode + } } module Consistency = MakeConsistency; From c04f0beb8a41cce5bb89eb1a8d453043075e8658 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 12 Aug 2024 14:08:23 +0200 Subject: [PATCH 10/37] Update DataFlowConsistency.expected --- .../library-tests/FlowSummary/DataFlowConsistency.expected | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/javascript/ql/test/library-tests/FlowSummary/DataFlowConsistency.expected b/javascript/ql/test/library-tests/FlowSummary/DataFlowConsistency.expected index 5a967f1256e3..892f306f30e4 100644 --- a/javascript/ql/test/library-tests/FlowSummary/DataFlowConsistency.expected +++ b/javascript/ql/test/library-tests/FlowSummary/DataFlowConsistency.expected @@ -16,10 +16,9 @@ postHasUniquePre uniquePostUpdate postIsInSameCallable reverseRead -| tst.js:109:11:113:3 | 'arguments' object of anonymous function | Origin of readStep is missing a PostUpdateNode. | +| tst.js:109:11:113:3 | [dynamic parameter array] | Origin of readStep is missing a PostUpdateNode. | | tst.js:267:28:267:31 | map3 | Origin of readStep is missing a PostUpdateNode. | argHasPostUpdate -| tst.js:219:18:219:27 | [source()] | ArgumentNode is missing PostUpdateNode. | postWithInFlow | file://:0:0:0:0 | [summary] to write: Argument[1] in Array method with flow into callback | PostUpdateNode should not be the target of local flow. | | file://:0:0:0:0 | [summary] to write: Argument[1] in Array#filter | PostUpdateNode should not be the target of local flow. | From 5c7e623c472380dd3c1662ba74a29b1b7ec071e0 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 12 Aug 2024 14:08:43 +0200 Subject: [PATCH 11/37] JS: Add some tests for missing handling of dynamic args in flow summaries --- .../library-tests/FlowSummary/test.expected | 7 ++++++ .../ql/test/library-tests/FlowSummary/tst.js | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/javascript/ql/test/library-tests/FlowSummary/test.expected b/javascript/ql/test/library-tests/FlowSummary/test.expected index e69de29bb2d1..28b528767d83 100644 --- a/javascript/ql/test/library-tests/FlowSummary/test.expected +++ b/javascript/ql/test/library-tests/FlowSummary/test.expected @@ -0,0 +1,7 @@ +| library-tests/FlowSummary/tst.js:278 | expected an alert, but found none | NOT OK | ConsistencyConfig | +| library-tests/FlowSummary/tst.js:282 | expected an alert, but found none | NOT OK | ConsistencyConfig | +| library-tests/FlowSummary/tst.js:283 | expected an alert, but found none | NOT OK | ConsistencyConfig | +| library-tests/FlowSummary/tst.js:286 | expected an alert, but found none | NOT OK | ConsistencyConfig | +| library-tests/FlowSummary/tst.js:287 | expected an alert, but found none | NOT OK | ConsistencyConfig | +| library-tests/FlowSummary/tst.js:290 | expected an alert, but found none | NOT OK | ConsistencyConfig | +| library-tests/FlowSummary/tst.js:291 | expected an alert, but found none | NOT OK | ConsistencyConfig | diff --git a/javascript/ql/test/library-tests/FlowSummary/tst.js b/javascript/ql/test/library-tests/FlowSummary/tst.js index aea6cf4f6fa1..ac0ffb0003e4 100644 --- a/javascript/ql/test/library-tests/FlowSummary/tst.js +++ b/javascript/ql/test/library-tests/FlowSummary/tst.js @@ -268,3 +268,26 @@ function m17() { sink(value); // NOT OK } } + +function m18() { + const staticParam0 = mkSummary("Argument[0]", "ReturnValue"); + const staticParam1 = mkSummary("Argument[1]", "ReturnValue"); + const dynamicParam0 = mkSummary("Argument[0..]", "ReturnValue"); + const dynamicParam1 = mkSummary("Argument[1..]", "ReturnValue"); + + sink(staticParam0(...source())); // NOT OK + sink(staticParam0("safe", ...source())); // OK + sink(staticParam0(source(), ...["safe"])); // NOT OK + + sink(staticParam1(...source())); // NOT OK + sink(staticParam1("safe", ...source())); // NOT OK + sink(staticParam1(source(), ...["safe"])); // OK + + sink(dynamicParam0(...source())); // NOT OK + sink(dynamicParam0("safe", ...source())); // NOT OK + sink(dynamicParam0(source(), ...["safe"])); // NOT OK + + sink(dynamicParam1(...source())); // NOT OK + sink(dynamicParam1("safe", ...source())); // NOT OK + sink(dynamicParam1(source(), ...["safe"])); // OK +} From 53a2a66dd0e7496e6cbf234c6723555efed95b18 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 12 Aug 2024 14:13:28 +0200 Subject: [PATCH 12/37] Add new nodes to early stage --- .../lib/semmle/javascript/dataflow/internal/DataFlowNode.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll index ab152e34f9d4..7db6e3a3c71c 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll @@ -118,7 +118,8 @@ private class TEarlyStageNode = TFunctionSelfReferenceNode or TDestructuredModuleImportNode or THtmlAttributeNode or TFunctionReturnNode or TExceptionalFunctionReturnNode or TExceptionalInvocationReturnNode or TGlobalAccessPathRoot or TTemplatePlaceholderTag or TReflectiveParametersNode or - TExprPostUpdateNode or TConstructorThisArgumentNode; + TExprPostUpdateNode or TConstructorThisArgumentNode or TStaticArgumentArrayNode or + TDynamicArgumentArrayNode or TStaticParameterArrayNode or TDynamicParameterArrayNode; /** * A data-flow node that is not a flow summary node. From acdc896c043dd31398f1d456b50c6b51b7e1c4fa Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 12 Aug 2024 14:38:19 +0200 Subject: [PATCH 13/37] JS: Support for dynamic args to flow summaries --- .../internal/DataFlowImplConsistency.qll | 6 ++++ .../dataflow/internal/DataFlowNode.qll | 1 + .../dataflow/internal/DataFlowPrivate.qll | 32 +++++++++++++++++++ .../dataflow/internal/FlowSummaryPrivate.qll | 2 -- .../internal/flow_summaries/Arrays.qll | 15 +++------ .../library-tests/FlowSummary/test.expected | 7 ---- .../ql/test/library-tests/FlowSummary/tst.js | 24 +++++++++----- 7 files changed, 59 insertions(+), 28 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowImplConsistency.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowImplConsistency.qll index 5b166b891190..aa892c810dbe 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowImplConsistency.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowImplConsistency.qll @@ -24,6 +24,8 @@ private module ConsistencyConfig implements InputSig { or n instanceof FlowSummaryIntermediateAwaitStoreNode or + n instanceof FlowSummaryDynamicParameterArrayNode + or n instanceof GenericSynthesizedNode or n = DataFlow::globalAccessPathRootPseudoNode() @@ -43,6 +45,10 @@ private module ConsistencyConfig implements InputSig { node instanceof TStaticArgumentArrayNode or node instanceof TDynamicArgumentArrayNode } + + predicate reverseReadExclude(DataFlow::Node node) { + node instanceof FlowSummaryDynamicParameterArrayNode + } } module Consistency = MakeConsistency; diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll index 7db6e3a3c71c..59e0b65e58fa 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll @@ -80,6 +80,7 @@ private module Cached { TConstructorThisArgumentNode(InvokeExpr e) { e instanceof NewExpr or e instanceof SuperCall } or TConstructorThisPostUpdate(Constructor ctor) or TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or + TFlowSummaryDynamicParameterArrayNode(FlowSummaryImpl::Public::SummarizedCallable callable) or TFlowSummaryIntermediateAwaitStoreNode(FlowSummaryImpl::Private::SummaryNode sn) { // NOTE: This dependency goes through the 'Steps' module whose instantiation depends on the call graph, // but the specific predicate we're referering to does not use that information. diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll index 99929776e71a..fe7027fe7059 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll @@ -30,6 +30,19 @@ class FlowSummaryNode extends DataFlow::Node, TFlowSummaryNode { override string toString() { result = this.getSummaryNode().toString() } } +class FlowSummaryDynamicParameterArrayNode extends DataFlow::Node, + TFlowSummaryDynamicParameterArrayNode +{ + private FlowSummaryImpl::Public::SummarizedCallable callable; + + FlowSummaryDynamicParameterArrayNode() { this = TFlowSummaryDynamicParameterArrayNode(callable) } + + FlowSummaryImpl::Public::SummarizedCallable getSummarizedCallable() { result = callable } + + cached + override string toString() { result = "[dynamic parameter array] " + callable } +} + class FlowSummaryIntermediateAwaitStoreNode extends DataFlow::Node, TFlowSummaryIntermediateAwaitStoreNode { @@ -342,6 +355,12 @@ private predicate isParameterNodeImpl(Node p, DataFlowCallable c, ParameterPosit FlowSummaryImpl::Private::summaryParameterNode(summaryNode.getSummaryNode(), pos) and c.asLibraryCallable() = summaryNode.getSummarizedCallable() ) + or + exists(FlowSummaryImpl::Public::SummarizedCallable callable | + c.asLibraryCallable() = callable and + pos.isDynamicArgumentArray() and + p = TFlowSummaryDynamicParameterArrayNode(callable) + ) } predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) { @@ -410,6 +429,8 @@ DataFlowCallable nodeGetEnclosingCallable(Node node) { or result.asLibraryCallable() = node.(FlowSummaryNode).getSummarizedCallable() or + result.asLibraryCallable() = node.(FlowSummaryDynamicParameterArrayNode).getSummarizedCallable() + or result.asLibraryCallable() = node.(FlowSummaryIntermediateAwaitStoreNode).getSummarizedCallable() or node = TGenericSynthesizedNode(_, _, result) @@ -1118,6 +1139,17 @@ predicate readStep(Node node1, ContentSet c, Node node2) { storeContent.isUnknownArrayElement() else storeContent.asArrayIndex() = n + c.asArrayIndex() ) + or + exists(FlowSummaryNode parameter, ParameterPosition pos | + FlowSummaryImpl::Private::summaryParameterNode(parameter.getSummaryNode(), pos) and + node1 = TFlowSummaryDynamicParameterArrayNode(parameter.getSummarizedCallable()) and + node2 = parameter and + ( + c.asArrayIndex() = pos.asPositional() + or + c = ContentSet::arrayElementLowerBound(pos.asPositionalLowerBound()) + ) + ) } /** Gets the post-update node for which `node` is the corresponding pre-update node. */ diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll index ca38d30e9013..3611d34667ea 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll @@ -35,8 +35,6 @@ private predicate positionName(ParameterPosition pos, string operand) { or pos.isFunctionSelfReference() and operand = "function" or - pos.isDynamicArgumentArray() and operand = "arguments-array" // TODO: remove and handle automatically - or operand = pos.asPositionalLowerBound() + ".." } diff --git a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll index 8ab74e217b10..0723cbf3767f 100644 --- a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll +++ b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll @@ -101,17 +101,11 @@ class ArrayConstructorSummary extends SummarizedCallable { override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { preservesValue = true and - ( - input = "Argument[0..]" and - output = "ReturnValue.ArrayElement" - or - input = "Argument[arguments-array].WithArrayElement" and - output = "ReturnValue" - ) + input = "Argument[0..]" and + output = "ReturnValue.ArrayElement" or - // TODO: workaround for WithArrayElement not being converted to a taint step preservesValue = false and - input = "Argument[arguments-array]" and + input = "Argument[0..]" and output = "ReturnValue" } } @@ -437,8 +431,7 @@ class PushLike extends SummarizedCallable { override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { preservesValue = true and - // TODO: make it so `arguments-array` is handled without needing to reference it explicitly in every flow-summary - input = ["Argument[0..]", "Argument[arguments-array].ArrayElement"] and + input = "Argument[0..]" and output = "Argument[this].ArrayElement" } } diff --git a/javascript/ql/test/library-tests/FlowSummary/test.expected b/javascript/ql/test/library-tests/FlowSummary/test.expected index 28b528767d83..e69de29bb2d1 100644 --- a/javascript/ql/test/library-tests/FlowSummary/test.expected +++ b/javascript/ql/test/library-tests/FlowSummary/test.expected @@ -1,7 +0,0 @@ -| library-tests/FlowSummary/tst.js:278 | expected an alert, but found none | NOT OK | ConsistencyConfig | -| library-tests/FlowSummary/tst.js:282 | expected an alert, but found none | NOT OK | ConsistencyConfig | -| library-tests/FlowSummary/tst.js:283 | expected an alert, but found none | NOT OK | ConsistencyConfig | -| library-tests/FlowSummary/tst.js:286 | expected an alert, but found none | NOT OK | ConsistencyConfig | -| library-tests/FlowSummary/tst.js:287 | expected an alert, but found none | NOT OK | ConsistencyConfig | -| library-tests/FlowSummary/tst.js:290 | expected an alert, but found none | NOT OK | ConsistencyConfig | -| library-tests/FlowSummary/tst.js:291 | expected an alert, but found none | NOT OK | ConsistencyConfig | diff --git a/javascript/ql/test/library-tests/FlowSummary/tst.js b/javascript/ql/test/library-tests/FlowSummary/tst.js index ac0ffb0003e4..264c304f0f31 100644 --- a/javascript/ql/test/library-tests/FlowSummary/tst.js +++ b/javascript/ql/test/library-tests/FlowSummary/tst.js @@ -275,19 +275,27 @@ function m18() { const dynamicParam0 = mkSummary("Argument[0..]", "ReturnValue"); const dynamicParam1 = mkSummary("Argument[1..]", "ReturnValue"); - sink(staticParam0(...source())); // NOT OK - sink(staticParam0("safe", ...source())); // OK + sink(staticParam0(...[source()])); // NOT OK + sink(staticParam0(...["safe", source()])); // OK + sink(staticParam0(...[source(), "safe", ])); // NOT OK + sink(staticParam0("safe", ...[source()])); // OK sink(staticParam0(source(), ...["safe"])); // NOT OK - sink(staticParam1(...source())); // NOT OK - sink(staticParam1("safe", ...source())); // NOT OK + sink(staticParam1(...[source()])); // OK + sink(staticParam1(...["safe", source()])); // NOT OK + sink(staticParam1(...[source(), "safe", ])); // OK + sink(staticParam1("safe", ...[source()])); // NOT OK sink(staticParam1(source(), ...["safe"])); // OK - sink(dynamicParam0(...source())); // NOT OK - sink(dynamicParam0("safe", ...source())); // NOT OK + sink(dynamicParam0(...[source()])); // NOT OK + sink(dynamicParam0(...["safe", source()])); // NOT OK + sink(dynamicParam0(...[source(), "safe", ])); // NOT OK + sink(dynamicParam0("safe", ...[source()])); // NOT OK sink(dynamicParam0(source(), ...["safe"])); // NOT OK - sink(dynamicParam1(...source())); // NOT OK - sink(dynamicParam1("safe", ...source())); // NOT OK + sink(dynamicParam1(...[source()])); // OK + sink(dynamicParam1(...["safe", source()])); // NOT OK + sink(dynamicParam1(...[source(), "safe", ])); // OK + sink(dynamicParam1("safe", ...[source()])); // NOT OK sink(dynamicParam1(source(), ...["safe"])); // OK } From 6a083136d77746c0e91f4059db6501ed3b817565 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 12 Aug 2024 14:52:00 +0200 Subject: [PATCH 14/37] JS: Hide some nodes --- .../dataflow/internal/DataFlowPrivate.qll | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll index fe7027fe7059..d7791c0f59ee 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll @@ -487,6 +487,8 @@ predicate nodeIsHidden(Node node) { or node instanceof FlowSummaryNode or + node instanceof FlowSummaryDynamicParameterArrayNode + or node instanceof FlowSummaryIntermediateAwaitStoreNode or node instanceof CaptureNode @@ -499,6 +501,18 @@ predicate nodeIsHidden(Node node) { node.(DataFlow::ExprPostUpdateNode).getExpr() instanceof Function or node instanceof GenericSynthesizedNode + or + node instanceof StaticArgumentArrayNode + or + node instanceof DynamicArgumentArrayNode + or + node instanceof DynamicArgumentStoreNode + or + node instanceof StaticParameterArrayNode + or + node instanceof DynamicParameterArrayNode + or + node instanceof RestParameterStoreNode } predicate neverSkipInPathGraph(Node node) { From 079a622cf99c7341a2d39efcfe04356fc58e2cd9 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 14 Aug 2024 12:02:58 +0200 Subject: [PATCH 15/37] JS: Add tests showing missing taint flow When the spread argument itself is tained and not inside any content, the read steps currently fail to propagate the data. --- .../ql/test/library-tests/TripleDot/tst.js | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/javascript/ql/test/library-tests/TripleDot/tst.js b/javascript/ql/test/library-tests/TripleDot/tst.js index 3206ad657d00..aa53a49bb8e5 100644 --- a/javascript/ql/test/library-tests/TripleDot/tst.js +++ b/javascript/ql/test/library-tests/TripleDot/tst.js @@ -112,3 +112,29 @@ function t10() { } target(source('t10.1'), source('t10.2'), source('t10.3')); } + +function t11() { + function target(x, y) { + sink(x); // $ MISSING: hasTaintFlow=t11.1 + sink(y); // $ MISSING: hasTaintFlow=t11.1 + } + target(...source('t11.1')); +} + +function t12() { + function target(x, y) { + sink(x); + sink(y); // $ MISSING: hasTaintFlow=t12.1 + } + target("safe", ...source('t12.1')); +} + +function t13() { + function target(x, y, ...rest) { + sink(x); + sink(y); // $ MISSING: hasTaintFlow=t13.1 + sink(rest); // $ MISSING: hasTaintFlow=t13.1 + sink(rest[0]); // $ MISSING: hasTaintFlow=t13.1 + } + target("safe", ...source('t13.1')); +} From 895cb872ada8427a856a104207b86df85d40081a Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 14 Aug 2024 13:13:58 +0200 Subject: [PATCH 16/37] JS: Add taint into dynamic argument array --- .../dataflow/internal/TaintTrackingPrivate.qll | 8 ++++++++ javascript/ql/test/library-tests/TripleDot/tst.js | 12 ++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll index 7b4d8a8e94b4..400640f69454 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll @@ -1,5 +1,6 @@ private import javascript private import semmle.javascript.dataflow.internal.DataFlowPrivate +private import semmle.javascript.dataflow.internal.DataFlowNode private import semmle.javascript.dataflow.internal.Contents::Public private import semmle.javascript.dataflow.internal.sharedlib.FlowSummaryImpl as FlowSummaryImpl private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate @@ -18,6 +19,13 @@ predicate defaultAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) or FlowSummaryPrivate::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), ContentSet::arrayElement(), node2.(FlowSummaryNode).getSummaryNode()) + or + // If the spread argument itself is tainted (not inside a content), store it into the dynamic argument array. + exists(InvokeExpr invoke, Content c | + node1 = TValueNode(invoke.getAnArgument().stripParens().(SpreadElement).getOperand()) and + node2 = TDynamicArgumentStoreNode(invoke, c) and + c.isUnknownArrayElement() + ) } predicate defaultAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2, string model) { diff --git a/javascript/ql/test/library-tests/TripleDot/tst.js b/javascript/ql/test/library-tests/TripleDot/tst.js index aa53a49bb8e5..1a0f000fd501 100644 --- a/javascript/ql/test/library-tests/TripleDot/tst.js +++ b/javascript/ql/test/library-tests/TripleDot/tst.js @@ -115,24 +115,24 @@ function t10() { function t11() { function target(x, y) { - sink(x); // $ MISSING: hasTaintFlow=t11.1 - sink(y); // $ MISSING: hasTaintFlow=t11.1 + sink(x); // $ hasTaintFlow=t11.1 + sink(y); // $ hasTaintFlow=t11.1 } target(...source('t11.1')); } function t12() { function target(x, y) { - sink(x); - sink(y); // $ MISSING: hasTaintFlow=t12.1 + sink(x); // $ SPURIOUS: hasTaintFlow=t12.1 + sink(y); // $ hasTaintFlow=t12.1 } target("safe", ...source('t12.1')); } function t13() { function target(x, y, ...rest) { - sink(x); - sink(y); // $ MISSING: hasTaintFlow=t13.1 + sink(x); // $ SPURIOUS: hasTaintFlow=t13.1 + sink(y); // $ hasTaintFlow=t13.1 sink(rest); // $ MISSING: hasTaintFlow=t13.1 sink(rest[0]); // $ MISSING: hasTaintFlow=t13.1 } From 5084d0260f822aefbe2ebbf1fc9a7365e16a4a29 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 14 Aug 2024 14:02:56 +0200 Subject: [PATCH 17/37] Update tests.expected The 'arguments' node is only materialised for functions that use 'arguments --- .../library-tests/DataFlow/tests.expected | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/javascript/ql/test/library-tests/DataFlow/tests.expected b/javascript/ql/test/library-tests/DataFlow/tests.expected index 3b127d2dfa0e..8d333f1b9e0a 100644 --- a/javascript/ql/test/library-tests/DataFlow/tests.expected +++ b/javascript/ql/test/library-tests/DataFlow/tests.expected @@ -15,7 +15,6 @@ basicBlock | arguments.js:1:1:12:4 | (functi ... );\\n})() | arguments.js:1:1:1:0 | entry node of | | arguments.js:1:1:12:4 | exceptional return of (functi ... );\\n})() | arguments.js:1:1:1:0 | entry node of | | arguments.js:1:2:1:1 | this | arguments.js:1:2:1:1 | entry node of functio ... , 3);\\n} | -| arguments.js:1:2:12:1 | 'arguments' object of anonymous function | arguments.js:1:2:1:1 | entry node of functio ... , 3);\\n} | | arguments.js:1:2:12:1 | [function self-reference] functio ... , 3);\\n} | arguments.js:1:2:1:1 | entry node of functio ... , 3);\\n} | | arguments.js:1:2:12:1 | exceptional return of anonymous function | arguments.js:1:2:1:1 | entry node of functio ... , 3);\\n} | | arguments.js:1:2:12:1 | functio ... , 3);\\n} | arguments.js:1:1:1:0 | entry node of | @@ -70,7 +69,6 @@ basicBlock | arguments.js:11:13:11:13 | 3 | arguments.js:1:2:1:1 | entry node of functio ... , 3);\\n} | | eval.js:1:1:1:0 | this | eval.js:1:1:1:0 | entry node of | | eval.js:1:1:1:0 | this | eval.js:1:1:1:0 | entry node of functio ... eval`\\n} | -| eval.js:1:1:5:1 | 'arguments' object of function k | eval.js:1:1:1:0 | entry node of functio ... eval`\\n} | | eval.js:1:1:5:1 | [function self-reference] functio ... eval`\\n} | eval.js:1:1:1:0 | entry node of functio ... eval`\\n} | | eval.js:1:1:5:1 | exceptional return of function k | eval.js:1:1:1:0 | entry node of functio ... eval`\\n} | | eval.js:1:1:5:1 | functio ... eval`\\n} | eval.js:1:1:1:0 | entry node of | @@ -91,7 +89,6 @@ basicBlock | sources.js:1:5:1:12 | (x => x) | sources.js:1:1:1:0 | entry node of | | sources.js:1:6:1:6 | x | sources.js:1:6:1:5 | entry node of x => x | | sources.js:1:6:1:6 | x | sources.js:1:6:1:5 | entry node of x => x | -| sources.js:1:6:1:11 | 'arguments' object of anonymous function | sources.js:1:6:1:5 | entry node of x => x | | sources.js:1:6:1:11 | [function self-reference] x => x | sources.js:1:6:1:5 | entry node of x => x | | sources.js:1:6:1:11 | exceptional return of anonymous function | sources.js:1:6:1:5 | entry node of x => x | | sources.js:1:6:1:11 | return of anonymous function | sources.js:1:6:1:5 | entry node of x => x | @@ -101,7 +98,6 @@ basicBlock | sources.js:3:1:5:6 | (functi ... \\n})(23) | sources.js:1:1:1:0 | entry node of | | sources.js:3:1:5:6 | exceptional return of (functi ... \\n})(23) | sources.js:1:1:1:0 | entry node of | | sources.js:3:2:3:1 | this | sources.js:3:2:3:1 | entry node of functio ... x+19;\\n} | -| sources.js:3:2:5:1 | 'arguments' object of anonymous function | sources.js:3:2:3:1 | entry node of functio ... x+19;\\n} | | sources.js:3:2:5:1 | [function self-reference] functio ... x+19;\\n} | sources.js:3:2:3:1 | entry node of functio ... x+19;\\n} | | sources.js:3:2:5:1 | exceptional return of anonymous function | sources.js:3:2:3:1 | entry node of functio ... x+19;\\n} | | sources.js:3:2:5:1 | functio ... x+19;\\n} | sources.js:1:1:1:0 | entry node of | @@ -114,7 +110,6 @@ basicBlock | sources.js:5:4:5:5 | 23 | sources.js:1:1:1:0 | entry node of | | sources.js:7:1:7:3 | /x/ | sources.js:1:1:1:0 | entry node of | | sources.js:9:1:9:0 | this | sources.js:9:1:9:0 | entry node of functio ... ey; }\\n} | -| sources.js:9:1:12:1 | 'arguments' object of function foo | sources.js:9:1:9:0 | entry node of functio ... ey; }\\n} | | sources.js:9:1:12:1 | [function self-reference] functio ... ey; }\\n} | sources.js:9:1:9:0 | entry node of functio ... ey; }\\n} | | sources.js:9:1:12:1 | exceptional return of function foo | sources.js:12:2:12:1 | exit node of functio ... ey; }\\n} | | sources.js:9:1:12:1 | functio ... ey; }\\n} | sources.js:1:1:1:0 | entry node of | @@ -152,7 +147,6 @@ basicBlock | tst2.ts:4:3:4:3 | x | tst2.ts:1:1:1:0 | entry node of | | tst2.ts:7:1:7:0 | A | tst2.ts:7:1:7:0 | entry node of functio ... = 23;\\n} | | tst2.ts:7:1:7:0 | this | tst2.ts:7:1:7:0 | entry node of functio ... = 23;\\n} | -| tst2.ts:7:1:9:1 | 'arguments' object of function setX | tst2.ts:7:1:7:0 | entry node of functio ... = 23;\\n} | | tst2.ts:7:1:9:1 | [function self-reference] functio ... = 23;\\n} | tst2.ts:7:1:7:0 | entry node of functio ... = 23;\\n} | | tst2.ts:7:1:9:1 | exceptional return of function setX | tst2.ts:7:1:7:0 | entry node of functio ... = 23;\\n} | | tst2.ts:7:1:9:1 | functio ... = 23;\\n} | tst2.ts:1:1:1:0 | entry node of | @@ -174,7 +168,6 @@ basicBlock | tst2.ts:13:7:13:16 | StringList | tst2.ts:1:1:1:0 | entry node of | | tst2.ts:13:26:13:29 | List | tst2.ts:1:1:1:0 | entry node of | | tst2.ts:13:26:13:37 | List | tst2.ts:1:1:1:0 | entry node of | -| tst2.ts:13:39:13:38 | 'arguments' object of default constructor of class StringList | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } | | tst2.ts:13:39:13:38 | (...arg ... rgs); } | tst2.ts:1:1:1:0 | entry node of | | tst2.ts:13:39:13:38 | ...args | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } | | tst2.ts:13:39:13:38 | [function self-reference] (...arg ... rgs); } | tst2.ts:13:39:13:38 | entry node of (...arg ... rgs); } | @@ -243,7 +236,6 @@ basicBlock | tst.js:16:1:20:9 | (functi ... ("arg") | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:16:1:20:9 | exceptional return of (functi ... ("arg") | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:16:2:16:1 | this | tst.js:16:2:16:1 | entry node of functio ... n "";\\n} | -| tst.js:16:2:20:1 | 'arguments' object of function f | tst.js:16:2:16:1 | entry node of functio ... n "";\\n} | | tst.js:16:2:20:1 | [function self-reference] functio ... n "";\\n} | tst.js:16:2:16:1 | entry node of functio ... n "";\\n} | | tst.js:16:2:20:1 | exceptional return of function f | tst.js:20:2:20:1 | exit node of functio ... n "";\\n} | | tst.js:16:2:20:1 | functio ... n "";\\n} | tst.js:16:1:20:10 | (functi ... "arg"); | @@ -278,7 +270,6 @@ basicBlock | tst.js:28:1:30:3 | (() =>\\n ... les\\n)() | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:28:1:30:3 | exceptional return of (() =>\\n ... les\\n)() | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:28:2:28:1 | x | tst.js:28:2:28:1 | entry node of () =>\\n x | -| tst.js:28:2:29:3 | 'arguments' object of anonymous function | tst.js:28:2:28:1 | entry node of () =>\\n x | | tst.js:28:2:29:3 | () =>\\n x | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:28:2:29:3 | [function self-reference] () =>\\n x | tst.js:28:2:28:1 | entry node of () =>\\n x | | tst.js:28:2:29:3 | exceptional return of anonymous function | tst.js:28:2:28:1 | entry node of () =>\\n x | @@ -286,7 +277,6 @@ basicBlock | tst.js:29:3:29:3 | x | tst.js:28:2:28:1 | entry node of () =>\\n x | | tst.js:32:1:32:0 | this | tst.js:32:1:32:0 | entry node of functio ... ables\\n} | | tst.js:32:1:32:0 | x | tst.js:32:1:32:0 | entry node of functio ... ables\\n} | -| tst.js:32:1:34:1 | 'arguments' object of function g | tst.js:32:1:32:0 | entry node of functio ... ables\\n} | | tst.js:32:1:34:1 | [function self-reference] functio ... ables\\n} | tst.js:32:1:32:0 | entry node of functio ... ables\\n} | | tst.js:32:1:34:1 | exceptional return of function g | tst.js:32:1:32:0 | entry node of functio ... ables\\n} | | tst.js:32:1:34:1 | functio ... ables\\n} | tst.js:16:1:20:10 | (functi ... "arg"); | @@ -311,7 +301,6 @@ basicBlock | tst.js:39:3:41:3 | m() {\\n this;\\n } | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:39:3:41:3 | m() {\\n this;\\n } | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:39:4:39:3 | this | tst.js:39:4:39:3 | entry node of () {\\n this;\\n } | -| tst.js:39:4:41:3 | 'arguments' object of method m | tst.js:39:4:39:3 | entry node of () {\\n this;\\n } | | tst.js:39:4:41:3 | () {\\n this;\\n } | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:39:4:41:3 | [function self-reference] () {\\n this;\\n } | tst.js:39:4:39:3 | entry node of () {\\n this;\\n } | | tst.js:39:4:41:3 | exceptional return of method m | tst.js:39:4:39:3 | entry node of () {\\n this;\\n } | @@ -337,7 +326,6 @@ basicBlock | tst.js:50:3:53:3 | constru ... et`\\n } | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:50:3:53:3 | constru ... et`\\n } | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:50:14:50:13 | this | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } | -| tst.js:50:14:53:3 | 'arguments' object of constructor of class A | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } | | tst.js:50:14:53:3 | () {\\n ... et`\\n } | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:50:14:53:3 | [function self-reference] () {\\n ... et`\\n } | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } | | tst.js:50:14:53:3 | exceptional return of constructor of class A | tst.js:50:14:50:13 | entry node of () {\\n ... et`\\n } | @@ -365,7 +353,6 @@ basicBlock | tst.js:62:1:62:4 | o::g | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:62:4:62:4 | g | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:64:1:64:0 | this | tst.js:64:1:64:0 | entry node of functio ... lysed\\n} | -| tst.js:64:1:67:1 | 'arguments' object of function h | tst.js:64:1:64:0 | entry node of functio ... lysed\\n} | | tst.js:64:1:67:1 | [function self-reference] functio ... lysed\\n} | tst.js:64:1:64:0 | entry node of functio ... lysed\\n} | | tst.js:64:1:67:1 | exceptional return of function h | tst.js:64:1:64:0 | entry node of functio ... lysed\\n} | | tst.js:64:1:67:1 | functio ... lysed\\n} | tst.js:16:1:20:10 | (functi ... "arg"); | @@ -390,7 +377,6 @@ basicBlock | tst.js:69:6:69:9 | next | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:69:11:69:12 | 23 | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:71:1:71:0 | this | tst.js:71:1:71:0 | entry node of async f ... lysed\\n} | -| tst.js:71:1:73:1 | 'arguments' object of function k | tst.js:71:1:71:0 | entry node of async f ... lysed\\n} | | tst.js:71:1:73:1 | [function self-reference] async f ... lysed\\n} | tst.js:71:1:71:0 | entry node of async f ... lysed\\n} | | tst.js:71:1:73:1 | async f ... lysed\\n} | tst.js:16:1:20:10 | (functi ... "arg"); | | tst.js:71:1:73:1 | exceptional return of function k | tst.js:71:1:71:0 | entry node of async f ... lysed\\n} | @@ -434,7 +420,6 @@ basicBlock | tst.js:87:1:96:2 | (functi ... r: 0\\n}) | tst.js:85:5:85:28 | vs2 = ( ... o) v ) | | tst.js:87:1:96:2 | exceptional return of (functi ... r: 0\\n}) | tst.js:85:5:85:28 | vs2 = ( ... o) v ) | | tst.js:87:2:87:1 | this | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} | -| tst.js:87:2:92:1 | 'arguments' object of anonymous function | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} | | tst.js:87:2:92:1 | [function self-reference] functio ... + z;\\n} | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} | | tst.js:87:2:92:1 | exceptional return of anonymous function | tst.js:87:2:87:1 | entry node of functio ... + z;\\n} | | tst.js:87:2:92:1 | functio ... + z;\\n} | tst.js:85:5:85:28 | vs2 = ( ... o) v ) | @@ -489,7 +474,6 @@ basicBlock | tst.js:98:1:103:17 | (functi ... 3, 0 ]) | tst.js:85:5:85:28 | vs2 = ( ... o) v ) | | tst.js:98:1:103:17 | exceptional return of (functi ... 3, 0 ]) | tst.js:85:5:85:28 | vs2 = ( ... o) v ) | | tst.js:98:2:98:1 | this | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} | -| tst.js:98:2:103:1 | 'arguments' object of anonymous function | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} | | tst.js:98:2:103:1 | [function self-reference] functio ... + z;\\n} | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} | | tst.js:98:2:103:1 | exceptional return of anonymous function | tst.js:98:2:98:1 | entry node of functio ... + z;\\n} | | tst.js:98:2:103:1 | functio ... + z;\\n} | tst.js:85:5:85:28 | vs2 = ( ... o) v ) | @@ -532,7 +516,6 @@ basicBlock | tst.js:105:6:105:6 | y | tst.js:105:6:105:6 | y | | tst.js:107:1:113:2 | (functi ... v2c;\\n}) | tst.js:107:1:113:3 | (functi ... 2c;\\n}); | | tst.js:107:2:107:1 | this | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} | -| tst.js:107:2:113:1 | 'arguments' object of anonymous function | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} | | tst.js:107:2:113:1 | [function self-reference] functio ... v2c;\\n} | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} | | tst.js:107:2:113:1 | exceptional return of anonymous function | tst.js:107:2:107:1 | entry node of functio ... v2c;\\n} | | tst.js:107:2:113:1 | functio ... v2c;\\n} | tst.js:107:1:113:3 | (functi ... 2c;\\n}); | @@ -1479,7 +1462,6 @@ sources | arguments.js:1:1:1:0 | this | | arguments.js:1:1:12:4 | (functi ... );\\n})() | | arguments.js:1:2:1:1 | this | -| arguments.js:1:2:12:1 | 'arguments' object of anonymous function | | arguments.js:1:2:12:1 | functio ... , 3);\\n} | | arguments.js:1:2:12:1 | return of anonymous function | | arguments.js:2:5:2:4 | this | @@ -1495,7 +1477,6 @@ sources | arguments.js:11:5:11:14 | f(1, 2, 3) | | eval.js:1:1:1:0 | this | | eval.js:1:1:1:0 | this | -| eval.js:1:1:5:1 | 'arguments' object of function k | | eval.js:1:1:5:1 | functio ... eval`\\n} | | eval.js:1:1:5:1 | return of function k | | eval.js:3:3:3:6 | eval | @@ -1505,18 +1486,15 @@ sources | sources.js:1:1:1:0 | this | | sources.js:1:1:1:12 | new (x => x) | | sources.js:1:6:1:6 | x | -| sources.js:1:6:1:11 | 'arguments' object of anonymous function | | sources.js:1:6:1:11 | return of anonymous function | | sources.js:1:6:1:11 | x => x | | sources.js:3:1:5:6 | (functi ... \\n})(23) | | sources.js:3:2:3:1 | this | -| sources.js:3:2:5:1 | 'arguments' object of anonymous function | | sources.js:3:2:5:1 | functio ... x+19;\\n} | | sources.js:3:2:5:1 | return of anonymous function | | sources.js:3:11:3:11 | x | | sources.js:7:1:7:3 | /x/ | | sources.js:9:1:9:0 | this | -| sources.js:9:1:12:1 | 'arguments' object of function foo | | sources.js:9:1:12:1 | functio ... ey; }\\n} | | sources.js:9:1:12:1 | return of function foo | | sources.js:9:14:9:18 | array | @@ -1526,14 +1504,12 @@ sources | tst2.ts:1:1:1:0 | this | | tst2.ts:3:3:3:8 | setX() | | tst2.ts:7:1:7:0 | this | -| tst2.ts:7:1:9:1 | 'arguments' object of function setX | | tst2.ts:7:1:9:1 | functio ... = 23;\\n} | | tst2.ts:7:1:9:1 | return of function setX | | tst2.ts:8:3:8:5 | A.x | | tst2.ts:11:11:11:13 | A.x | | tst2.ts:13:1:13:40 | class S ... ing> {} | | tst2.ts:13:26:13:29 | List | -| tst2.ts:13:39:13:38 | 'arguments' object of default constructor of class StringList | | tst2.ts:13:39:13:38 | (...arg ... rgs); } | | tst2.ts:13:39:13:38 | args | | tst2.ts:13:39:13:38 | return of default constructor of class StringList | @@ -1547,7 +1523,6 @@ sources | tst.js:4:9:4:12 | "hi" | | tst.js:16:1:20:9 | (functi ... ("arg") | | tst.js:16:2:16:1 | this | -| tst.js:16:2:20:1 | 'arguments' object of function f | | tst.js:16:2:20:1 | functio ... n "";\\n} | | tst.js:16:2:20:1 | return of function f | | tst.js:16:13:16:13 | a | @@ -1558,18 +1533,15 @@ sources | tst.js:20:4:20:8 | "arg" | | tst.js:22:7:22:18 | readFileSync | | tst.js:28:1:30:3 | (() =>\\n ... les\\n)() | -| tst.js:28:2:29:3 | 'arguments' object of anonymous function | | tst.js:28:2:29:3 | () =>\\n x | | tst.js:28:2:29:3 | return of anonymous function | | tst.js:32:1:32:0 | this | -| tst.js:32:1:34:1 | 'arguments' object of function g | | tst.js:32:1:34:1 | functio ... ables\\n} | | tst.js:32:1:34:1 | return of function g | | tst.js:32:12:32:12 | b | | tst.js:35:1:35:7 | g(true) | | tst.js:37:9:42:1 | {\\n x: ... ;\\n }\\n} | | tst.js:39:4:39:3 | this | -| tst.js:39:4:41:3 | 'arguments' object of method m | | tst.js:39:4:41:3 | () {\\n this;\\n } | | tst.js:39:4:41:3 | return of method m | | tst.js:43:1:43:3 | o.x | @@ -1581,7 +1553,6 @@ sources | tst.js:49:1:54:1 | class A ... `\\n }\\n} | | tst.js:49:17:49:17 | B | | tst.js:50:14:50:13 | this | -| tst.js:50:14:53:3 | 'arguments' object of constructor of class A | | tst.js:50:14:53:3 | () {\\n ... et`\\n } | | tst.js:50:14:53:3 | return of constructor of class A | | tst.js:51:5:51:13 | super(42) | @@ -1591,7 +1562,6 @@ sources | tst.js:61:3:61:5 | o.m | | tst.js:62:1:62:4 | o::g | | tst.js:64:1:64:0 | this | -| tst.js:64:1:67:1 | 'arguments' object of function h | | tst.js:64:1:67:1 | functio ... lysed\\n} | | tst.js:64:1:67:1 | return of function h | | tst.js:65:3:65:10 | yield 42 | @@ -1600,7 +1570,6 @@ sources | tst.js:69:1:69:9 | iter.next | | tst.js:69:1:69:13 | iter.next(23) | | tst.js:71:1:71:0 | this | -| tst.js:71:1:73:1 | 'arguments' object of function k | | tst.js:71:1:73:1 | async f ... lysed\\n} | | tst.js:71:1:73:1 | return of function k | | tst.js:72:3:72:11 | await p() | @@ -1613,7 +1582,6 @@ sources | tst.js:85:11:85:28 | ( for (v of o) v ) | | tst.js:87:1:96:2 | (functi ... r: 0\\n}) | | tst.js:87:2:87:1 | this | -| tst.js:87:2:92:1 | 'arguments' object of anonymous function | | tst.js:87:2:92:1 | functio ... + z;\\n} | | tst.js:87:2:92:1 | return of anonymous function | | tst.js:87:11:87:24 | { p: x, ...o } | @@ -1624,7 +1592,6 @@ sources | tst.js:92:4:96:1 | {\\n p: ... r: 0\\n} | | tst.js:98:1:103:17 | (functi ... 3, 0 ]) | | tst.js:98:2:98:1 | this | -| tst.js:98:2:103:1 | 'arguments' object of anonymous function | | tst.js:98:2:103:1 | functio ... + z;\\n} | | tst.js:98:2:103:1 | return of anonymous function | | tst.js:98:11:98:24 | [ x, ...rest ] | @@ -1634,7 +1601,6 @@ sources | tst.js:101:7:101:7 | z | | tst.js:103:4:103:16 | [ 19, 23, 0 ] | | tst.js:107:2:107:1 | this | -| tst.js:107:2:113:1 | 'arguments' object of anonymous function | | tst.js:107:2:113:1 | functio ... v2c;\\n} | | tst.js:107:2:113:1 | return of anonymous function | | tst.js:108:7:108:9 | v1a | From ac1dd1850e39ee45954e9990dd28dc37692c57c8 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 14 Aug 2024 14:33:52 +0200 Subject: [PATCH 18/37] JS: Remove taint step from array element to whole array --- .../javascript/dataflow/TaintTracking.qll | 12 ++++++---- .../TaintTracking/BasicTaintTracking.expected | 22 ++++++++++--------- .../TaintTracking/DataFlowTracking.expected | 2 ++ .../TaintTracking/arrays-init.js | 10 ++++----- .../library-tests/TaintTracking/call-apply.js | 6 ++--- 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll index 2574660fbebb..e6eccf6097d4 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll @@ -260,6 +260,14 @@ module TaintTracking { ) } + private class HeapLegacyTaintStep extends LegacyTaintStep { + override predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) { + // arrays with tainted elements are tainted (in old data flow) + succ.(DataFlow::ArrayCreationNode).getAnElement() = pred and + not any(PromiseAllCreation call).getArrayNode() = succ + } + } + /** * A taint propagating data flow edge through object or array elements and * promises. @@ -274,10 +282,6 @@ module TaintTracking { // spreading a tainted value into an array literal gives a tainted array succ.(DataFlow::ArrayCreationNode).getASpreadArgument() = pred or - // arrays with tainted elements and objects with tainted property names are tainted - succ.(DataFlow::ArrayCreationNode).getAnElement() = pred and - not any(PromiseAllCreation call).getArrayNode() = succ - or // reading from a tainted object yields a tainted result succ.(DataFlow::PropRead).getBase() = pred and not ( diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 91a7f3865166..57699721a377 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -1,5 +1,17 @@ legacyDataFlowDifference +| array-mutation.js:31:33:31:40 | source() | array-mutation.js:32:8:32:8 | h | only flow with OLD data flow library | +| array-mutation.js:35:36:35:43 | source() | array-mutation.js:36:8:36:8 | i | only flow with OLD data flow library | +| arrays-init.js:2:16:2:23 | source() | arrays-init.js:27:8:27:13 | arr[0] | only flow with OLD data flow library | +| arrays-init.js:2:16:2:23 | source() | arrays-init.js:33:8:33:13 | arr[0] | only flow with OLD data flow library | +| arrays-init.js:2:16:2:23 | source() | arrays-init.js:35:8:35:13 | arr[2] | only flow with OLD data flow library | +| arrays-init.js:2:16:2:23 | source() | arrays-init.js:36:8:36:13 | arr[3] | only flow with OLD data flow library | +| arrays-init.js:2:16:2:23 | source() | arrays-init.js:37:8:37:13 | arr[4] | only flow with OLD data flow library | | bound-function.js:27:8:27:15 | source() | bound-function.js:30:10:30:10 | y | only flow with OLD data flow library | +| call-apply.js:27:14:27:21 | source() | call-apply.js:24:8:24:11 | arg1 | only flow with NEW data flow library | +| call-apply.js:27:14:27:21 | source() | call-apply.js:32:6:32:35 | foo1.ap ... e, ""]) | only flow with NEW data flow library | +| call-apply.js:27:14:27:21 | source() | call-apply.js:34:6:34:29 | foo1_ap ... e, ""]) | only flow with NEW data flow library | +| call-apply.js:27:14:27:21 | source() | call-apply.js:41:6:41:28 | foo1_ca ... ource]) | only flow with OLD data flow library | +| call-apply.js:27:14:27:21 | source() | call-apply.js:59:10:59:21 | arguments[1] | only flow with OLD data flow library | | call-apply.js:45:8:45:15 | source() | call-apply.js:55:6:55:13 | foo(obj) | only flow with NEW data flow library | | callbacks.js:37:17:37:24 | source() | callbacks.js:38:35:38:35 | x | only flow with NEW data flow library | | callbacks.js:37:17:37:24 | source() | callbacks.js:41:10:41:10 | x | only flow with NEW data flow library | @@ -35,18 +47,11 @@ flow | array-mutation.js:19:18:19:25 | source() | array-mutation.js:20:8:20:8 | e | | array-mutation.js:23:13:23:20 | source() | array-mutation.js:24:8:24:8 | f | | array-mutation.js:27:16:27:23 | source() | array-mutation.js:28:8:28:8 | g | -| array-mutation.js:31:33:31:40 | source() | array-mutation.js:32:8:32:8 | h | -| array-mutation.js:35:36:35:43 | source() | array-mutation.js:36:8:36:8 | i | | array-mutation.js:39:17:39:24 | source() | array-mutation.js:40:8:40:8 | j | | arrays-init.js:2:16:2:23 | source() | arrays-init.js:17:8:17:13 | arr[1] | | arrays-init.js:2:16:2:23 | source() | arrays-init.js:22:8:22:13 | arr[6] | -| arrays-init.js:2:16:2:23 | source() | arrays-init.js:27:8:27:13 | arr[0] | | arrays-init.js:2:16:2:23 | source() | arrays-init.js:28:8:28:13 | arr[1] | -| arrays-init.js:2:16:2:23 | source() | arrays-init.js:33:8:33:13 | arr[0] | | arrays-init.js:2:16:2:23 | source() | arrays-init.js:34:8:34:13 | arr[1] | -| arrays-init.js:2:16:2:23 | source() | arrays-init.js:35:8:35:13 | arr[2] | -| arrays-init.js:2:16:2:23 | source() | arrays-init.js:36:8:36:13 | arr[3] | -| arrays-init.js:2:16:2:23 | source() | arrays-init.js:37:8:37:13 | arr[4] | | arrays-init.js:2:16:2:23 | source() | arrays-init.js:38:8:38:13 | arr[5] | | arrays-init.js:2:16:2:23 | source() | arrays-init.js:43:10:43:15 | arr[i] | | arrays-init.js:2:16:2:23 | source() | arrays-init.js:55:10:55:15 | arr[i] | @@ -69,11 +74,8 @@ flow | call-apply.js:27:14:27:21 | source() | call-apply.js:24:8:24:11 | arg1 | | call-apply.js:27:14:27:21 | source() | call-apply.js:29:6:29:32 | foo1.ca ... ce, "") | | call-apply.js:27:14:27:21 | source() | call-apply.js:32:6:32:35 | foo1.ap ... e, ""]) | -| call-apply.js:27:14:27:21 | source() | call-apply.js:33:6:33:35 | foo2.ap ... e, ""]) | | call-apply.js:27:14:27:21 | source() | call-apply.js:34:6:34:29 | foo1_ap ... e, ""]) | | call-apply.js:27:14:27:21 | source() | call-apply.js:40:6:40:28 | foo1_ca ... e, ""]) | -| call-apply.js:27:14:27:21 | source() | call-apply.js:41:6:41:28 | foo1_ca ... ource]) | -| call-apply.js:27:14:27:21 | source() | call-apply.js:59:10:59:21 | arguments[1] | | call-apply.js:27:14:27:21 | source() | call-apply.js:62:10:62:21 | arguments[0] | | call-apply.js:45:8:45:15 | source() | call-apply.js:55:6:55:13 | foo(obj) | | call-apply.js:81:17:81:24 | source() | call-apply.js:78:8:78:11 | this | diff --git a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected index de977a8ff92e..18ff982fa1e9 100644 --- a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected @@ -1,6 +1,8 @@ legacyDataFlowDifference | arrays-init.js:2:16:2:23 | source() | arrays-init.js:38:8:38:13 | arr[5] | only flow with NEW data flow library | | bound-function.js:27:8:27:15 | source() | bound-function.js:30:10:30:10 | y | only flow with OLD data flow library | +| call-apply.js:27:14:27:21 | source() | call-apply.js:24:8:24:11 | arg1 | only flow with NEW data flow library | +| call-apply.js:27:14:27:21 | source() | call-apply.js:32:6:32:35 | foo1.ap ... e, ""]) | only flow with NEW data flow library | | call-apply.js:27:14:27:21 | source() | call-apply.js:34:6:34:29 | foo1_ap ... e, ""]) | only flow with NEW data flow library | | call-apply.js:45:8:45:15 | source() | call-apply.js:55:6:55:13 | foo(obj) | only flow with NEW data flow library | | callbacks.js:37:17:37:24 | source() | callbacks.js:38:35:38:35 | x | only flow with NEW data flow library | diff --git a/javascript/ql/test/library-tests/TaintTracking/arrays-init.js b/javascript/ql/test/library-tests/TaintTracking/arrays-init.js index a0f3839d275c..7db1eaf682d2 100644 --- a/javascript/ql/test/library-tests/TaintTracking/arrays-init.js +++ b/javascript/ql/test/library-tests/TaintTracking/arrays-init.js @@ -24,17 +24,17 @@ console.log("=== access by index (init by [...]) ==="); var arr = [str, source]; - sink(arr[0]); // OK [INCONSISTENCY] + sink(arr[0]); // OK sink(arr[1]); // NOT OK sink(str); // OK console.log("=== access by index (init by [...], array.lenght > 5) ==="); var arr = [str, source, 'b', 'c', 'd', source]; - sink(arr[0]); // OK [INCONSISTENCY] + sink(arr[0]); // OK sink(arr[1]); // NOT OK - sink(arr[2]); // OK [INCONSISTENCY] - sink(arr[3]); // OK [INCONSISTENCY] - sink(arr[4]); // OK [INCONSISTENCY] + sink(arr[2]); // OK + sink(arr[3]); // OK + sink(arr[4]); // OK sink(arr[5]); // NOT OK console.log("=== access in for (init by [...]) ==="); diff --git a/javascript/ql/test/library-tests/TaintTracking/call-apply.js b/javascript/ql/test/library-tests/TaintTracking/call-apply.js index 0782ad71babe..4ed1bba7b718 100644 --- a/javascript/ql/test/library-tests/TaintTracking/call-apply.js +++ b/javascript/ql/test/library-tests/TaintTracking/call-apply.js @@ -30,7 +30,7 @@ sink(foo1.call(null, source, "")); // NOT OK sink(foo2.call(null, source, "")); // OK sink(foo1.apply(null, [source, ""])); // NOT OK -sink(foo2.apply(null, [source, ""])); // OK [INCONSISTENCY] +sink(foo2.apply(null, [source, ""])); // OK sink(foo1_apply([source, ""])); // NOT OK foo1_apply_sink([source, ""]); // This works, because we don't need a return after a call (the sink is inside the called function). @@ -38,7 +38,7 @@ foo1_apply_sink([source, ""]); // This works, because we don't need a return aft sink(foo1_apply.apply(["", source])); // OK sink(foo1_call([source, ""])); // NOT OK -sink(foo1_call(["", source])); // OK [INCONSISTENCY] +sink(foo1_call(["", source])); // OK var obj = { @@ -56,7 +56,7 @@ sink(foo(obj)); // NOT OK function argumentsObject() { function sinkArguments1() { - sink(arguments[1]); // OK [INCONSISTENCY] + sink(arguments[1]); // OK } function sinkArguments0() { sink(arguments[0]); // NOT OK From 34e6864fa3bcb4bd4d5eee5623e9389598cc7b62 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 14 Aug 2024 14:34:55 +0200 Subject: [PATCH 19/37] JS: Note issue with .apply() calls --- .../javascript/dataflow/internal/TaintTrackingPrivate.qll | 1 + .../ql/test/library-tests/TaintTracking/array-mutation.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll index 400640f69454..66c4fa2c60bc 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll @@ -25,6 +25,7 @@ predicate defaultAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) node1 = TValueNode(invoke.getAnArgument().stripParens().(SpreadElement).getOperand()) and node2 = TDynamicArgumentStoreNode(invoke, c) and c.isUnknownArrayElement() + // TODO: we need a similar case for .apply() calls ) } diff --git a/javascript/ql/test/library-tests/TaintTracking/array-mutation.js b/javascript/ql/test/library-tests/TaintTracking/array-mutation.js index cc581d34a253..e58b6fd99a92 100644 --- a/javascript/ql/test/library-tests/TaintTracking/array-mutation.js +++ b/javascript/ql/test/library-tests/TaintTracking/array-mutation.js @@ -29,11 +29,11 @@ function test(x, y) { let h = []; Array.prototype.push.apply(h, source()); - sink(h); // NOT OK + sink(h); // NOT OK [INCONSISTENCY] let i = []; Array.prototype.unshift.apply(i, source()); - sink(i); // NOT OK + sink(i); // NOT OK [INCONSISTENCY] let j = []; j[j.length] = source(); From 4389b5c999638c3a6999d44da9898efe9c1bec5c Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 14 Aug 2024 14:51:22 +0200 Subject: [PATCH 20/37] JS: Fix issue for .apply() calls --- .../dataflow/internal/DataFlowNode.qll | 3 ++ .../dataflow/internal/DataFlowPrivate.qll | 28 +++++++++++++++++++ .../internal/TaintTrackingPrivate.qll | 7 ++++- .../TaintTracking/BasicTaintTracking.expected | 4 +-- .../TaintTracking/array-mutation.js | 4 +-- 5 files changed, 41 insertions(+), 5 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll index 59e0b65e58fa..cd027d008623 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll @@ -55,6 +55,9 @@ private module Cached { invoke.isSpreadArgument(_) and storeContent = dynamicArgumentsContent() } or + TApplyCallTaintNode(MethodCallExpr node) { + node.getMethodName() = "apply" and exists(node.getArgument(1)) + } or TDestructuredModuleImportNode(ImportDeclaration decl) { exists(decl.getASpecifier().getImportedName()) } or diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll index d7791c0f59ee..25fa75e0e711 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll @@ -197,6 +197,28 @@ class DynamicParameterArrayNode extends DataFlow::Node, TDynamicParameterArrayNo override Location getLocation() { result = function.getLocation() } } +/** + * Node with taint input from the second argument of `.apply()` and with a store edge back into that same argument. + * + * This ensures that if `.apply()` is called with a tainted value (not inside a content) the taint is + * boxed in an `ArrayElement` content. This is necessary for the target function to propagate the taint. + */ +class ApplyCallTaintNode extends DataFlow::Node, TApplyCallTaintNode { + private MethodCallExpr apply; + + ApplyCallTaintNode() { this = TApplyCallTaintNode(apply) } + + override StmtContainer getContainer() { result = apply.getContainer() } + + override string toString() { result = "[apply call taint node]" } + + override Location getLocation() { result = apply.getArgument(1).getLocation() } + + MethodCallExpr getMethodCallExpr() { result = apply } + + DataFlow::Node getArrayNode() { result = apply.getArgument(1).flow() } +} + cached newtype TReturnKind = MkNormalReturnKind() or @@ -1233,6 +1255,12 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { c.asArrayIndex() = n and not n >= firstSpreadArgumentIndex(invoke) ) + or + exists(ApplyCallTaintNode taintNode | + node1 = taintNode and + node2 = taintNode.getArrayNode() and + c = ContentSet::arrayElementUnknown() + ) } /** diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll index 66c4fa2c60bc..9d17da244c5f 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll @@ -25,7 +25,12 @@ predicate defaultAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) node1 = TValueNode(invoke.getAnArgument().stripParens().(SpreadElement).getOperand()) and node2 = TDynamicArgumentStoreNode(invoke, c) and c.isUnknownArrayElement() - // TODO: we need a similar case for .apply() calls + ) + or + // If the array in an .apply() call is tainted (not inside a content), box it in an array element (similar to the case above). + exists(ApplyCallTaintNode taintNode | + node1 = taintNode.getArrayNode() and + node2 = taintNode ) } diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 57699721a377..fd2fb8bbc09d 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -1,6 +1,4 @@ legacyDataFlowDifference -| array-mutation.js:31:33:31:40 | source() | array-mutation.js:32:8:32:8 | h | only flow with OLD data flow library | -| array-mutation.js:35:36:35:43 | source() | array-mutation.js:36:8:36:8 | i | only flow with OLD data flow library | | arrays-init.js:2:16:2:23 | source() | arrays-init.js:27:8:27:13 | arr[0] | only flow with OLD data flow library | | arrays-init.js:2:16:2:23 | source() | arrays-init.js:33:8:33:13 | arr[0] | only flow with OLD data flow library | | arrays-init.js:2:16:2:23 | source() | arrays-init.js:35:8:35:13 | arr[2] | only flow with OLD data flow library | @@ -47,6 +45,8 @@ flow | array-mutation.js:19:18:19:25 | source() | array-mutation.js:20:8:20:8 | e | | array-mutation.js:23:13:23:20 | source() | array-mutation.js:24:8:24:8 | f | | array-mutation.js:27:16:27:23 | source() | array-mutation.js:28:8:28:8 | g | +| array-mutation.js:31:33:31:40 | source() | array-mutation.js:32:8:32:8 | h | +| array-mutation.js:35:36:35:43 | source() | array-mutation.js:36:8:36:8 | i | | array-mutation.js:39:17:39:24 | source() | array-mutation.js:40:8:40:8 | j | | arrays-init.js:2:16:2:23 | source() | arrays-init.js:17:8:17:13 | arr[1] | | arrays-init.js:2:16:2:23 | source() | arrays-init.js:22:8:22:13 | arr[6] | diff --git a/javascript/ql/test/library-tests/TaintTracking/array-mutation.js b/javascript/ql/test/library-tests/TaintTracking/array-mutation.js index e58b6fd99a92..cc581d34a253 100644 --- a/javascript/ql/test/library-tests/TaintTracking/array-mutation.js +++ b/javascript/ql/test/library-tests/TaintTracking/array-mutation.js @@ -29,11 +29,11 @@ function test(x, y) { let h = []; Array.prototype.push.apply(h, source()); - sink(h); // NOT OK [INCONSISTENCY] + sink(h); // NOT OK let i = []; Array.prototype.unshift.apply(i, source()); - sink(i); // NOT OK [INCONSISTENCY] + sink(i); // NOT OK let j = []; j[j.length] = source(); From 4e7bd9ddd84353bb6a15f8a24384a3fa9f3bdfa3 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 19 Aug 2024 11:42:30 +0200 Subject: [PATCH 21/37] JS: Update Arrays test now that array elements do not taint the whole array --- .../library-tests/Arrays/DataFlow.expected | 2 + .../library-tests/Arrays/TaintFlow.expected | 7 +- .../ql/test/library-tests/Arrays/arrays.js | 6 +- .../library-tests/Arrays/printAst.expected | 372 ++++++++++-------- 4 files changed, 214 insertions(+), 173 deletions(-) diff --git a/javascript/ql/test/library-tests/Arrays/DataFlow.expected b/javascript/ql/test/library-tests/Arrays/DataFlow.expected index 340f5dbe2302..21671a194645 100644 --- a/javascript/ql/test/library-tests/Arrays/DataFlow.expected +++ b/javascript/ql/test/library-tests/Arrays/DataFlow.expected @@ -24,3 +24,5 @@ flow | arrays.js:29:21:29:28 | "source" | arrays.js:50:8:50:17 | arr6.pop() | | arrays.js:33:37:33:44 | "source" | arrays.js:35:8:35:25 | arr4_variant.pop() | | arrays.js:53:4:53:11 | "source" | arrays.js:54:10:54:18 | ary.pop() | +| arrays.js:96:9:96:16 | "source" | arrays.js:96:8:96:40 | ["sourc ... ).pop() | +| arrays.js:97:9:97:16 | "source" | arrays.js:97:8:97:42 | ["sourc ... ).pop() | diff --git a/javascript/ql/test/library-tests/Arrays/TaintFlow.expected b/javascript/ql/test/library-tests/Arrays/TaintFlow.expected index 0f246a750bc9..70f5b29403da 100644 --- a/javascript/ql/test/library-tests/Arrays/TaintFlow.expected +++ b/javascript/ql/test/library-tests/Arrays/TaintFlow.expected @@ -1,11 +1,11 @@ legacyDataFlowDifference -| arrays.js:2:16:2:23 | "source" | arrays.js:39:8:39:24 | arr4_spread.pop() | only flow with OLD data flow library | flow | arrays.js:2:16:2:23 | "source" | arrays.js:5:8:5:14 | obj.foo | | arrays.js:2:16:2:23 | "source" | arrays.js:11:10:11:15 | arr[i] | | arrays.js:2:16:2:23 | "source" | arrays.js:15:27:15:27 | e | | arrays.js:2:16:2:23 | "source" | arrays.js:16:23:16:23 | e | | arrays.js:2:16:2:23 | "source" | arrays.js:20:8:20:16 | arr.pop() | +| arrays.js:2:16:2:23 | "source" | arrays.js:39:8:39:24 | arr4_spread.pop() | | arrays.js:2:16:2:23 | "source" | arrays.js:58:8:58:13 | arr[0] | | arrays.js:2:16:2:23 | "source" | arrays.js:61:10:61:10 | x | | arrays.js:2:16:2:23 | "source" | arrays.js:65:10:65:10 | x | @@ -26,5 +26,6 @@ flow | arrays.js:33:37:33:44 | "source" | arrays.js:35:8:35:25 | arr4_variant.pop() | | arrays.js:53:4:53:11 | "source" | arrays.js:54:10:54:18 | ary.pop() | | arrays.js:53:4:53:11 | "source" | arrays.js:55:10:55:12 | ary | -| arrays.js:95:9:95:16 | "source" | arrays.js:95:8:95:34 | ["sourc ... ) => x) | -| arrays.js:96:9:96:16 | "source" | arrays.js:96:8:96:36 | ["sourc ... => !!x) | +| arrays.js:95:9:95:16 | "source" | arrays.js:95:8:95:17 | ["source"] | +| arrays.js:96:9:96:16 | "source" | arrays.js:96:8:96:40 | ["sourc ... ).pop() | +| arrays.js:97:9:97:16 | "source" | arrays.js:97:8:97:42 | ["sourc ... ).pop() | diff --git a/javascript/ql/test/library-tests/Arrays/arrays.js b/javascript/ql/test/library-tests/Arrays/arrays.js index 9806ec2e395d..8c981a33a1f7 100644 --- a/javascript/ql/test/library-tests/Arrays/arrays.js +++ b/javascript/ql/test/library-tests/Arrays/arrays.js @@ -92,6 +92,8 @@ sink(arr.at(-1)); // NOT OK - sink(["source"].filter((x) => x)); // NOT OK - sink(["source"].filter((x) => !!x)); // NOT OK + sink(["source"]); // OK - for now, array element do not taint the entire array + sink(["source"].filter((x) => x).pop()); // NOT OK + sink(["source"].filter((x) => !!x).pop()); // NOT OK + }); diff --git a/javascript/ql/test/library-tests/Arrays/printAst.expected b/javascript/ql/test/library-tests/Arrays/printAst.expected index 2d0fdb458636..dbbeccd38a81 100644 --- a/javascript/ql/test/library-tests/Arrays/printAst.expected +++ b/javascript/ql/test/library-tests/Arrays/printAst.expected @@ -1,9 +1,9 @@ nodes -| arrays.js:1:1:97:2 | [ParExpr] (functi ... T OK }) | semmle.label | [ParExpr] (functi ... T OK }) | -| arrays.js:1:1:97:3 | [ExprStmt] (functi ... OK }); | semmle.label | [ExprStmt] (functi ... OK }); | -| arrays.js:1:1:97:3 | [ExprStmt] (functi ... OK }); | semmle.order | 1 | -| arrays.js:1:2:97:1 | [FunctionExpr] functio ... OT OK } | semmle.label | [FunctionExpr] functio ... OT OK } | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | semmle.label | [BlockStmt] { let ... OT OK } | +| arrays.js:1:1:99:2 | [ParExpr] (functi ... OK }) | semmle.label | [ParExpr] (functi ... OK }) | +| arrays.js:1:1:99:3 | [ExprStmt] (functi ... OK }); | semmle.label | [ExprStmt] (functi ... OK }); | +| arrays.js:1:1:99:3 | [ExprStmt] (functi ... OK }); | semmle.order | 1 | +| arrays.js:1:2:99:1 | [FunctionExpr] functio ... T OK } | semmle.label | [FunctionExpr] functio ... T OK } | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | semmle.label | [BlockStmt] { let ... T OK } | | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.label | [DeclStmt] let source = ... | | arrays.js:2:7:2:12 | [VarDecl] source | semmle.label | [VarDecl] source | | arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | semmle.label | [VariableDeclarator] source = "source" | @@ -394,29 +394,41 @@ nodes | arrays.js:93:15:93:16 | [UnaryExpr] -1 | semmle.label | [UnaryExpr] -1 | | arrays.js:93:16:93:16 | [Literal] 1 | semmle.label | [Literal] 1 | | arrays.js:95:3:95:6 | [VarRef] sink | semmle.label | [VarRef] sink | -| arrays.js:95:3:95:35 | [CallExpr] sink([" ... => x)) | semmle.label | [CallExpr] sink([" ... => x)) | -| arrays.js:95:3:95:36 | [ExprStmt] sink([" ... => x)); | semmle.label | [ExprStmt] sink([" ... => x)); | +| arrays.js:95:3:95:18 | [CallExpr] sink(["source"]) | semmle.label | [CallExpr] sink(["source"]) | +| arrays.js:95:3:95:19 | [ExprStmt] sink(["source"]); | semmle.label | [ExprStmt] sink(["source"]); | | arrays.js:95:8:95:17 | [ArrayExpr] ["source"] | semmle.label | [ArrayExpr] ["source"] | -| arrays.js:95:8:95:24 | [DotExpr] ["source"].filter | semmle.label | [DotExpr] ["source"].filter | -| arrays.js:95:8:95:34 | [MethodCallExpr] ["sourc ... ) => x) | semmle.label | [MethodCallExpr] ["sourc ... ) => x) | | arrays.js:95:9:95:16 | [Literal] "source" | semmle.label | [Literal] "source" | -| arrays.js:95:19:95:24 | [Label] filter | semmle.label | [Label] filter | -| arrays.js:95:26:95:33 | [ArrowFunctionExpr] (x) => x | semmle.label | [ArrowFunctionExpr] (x) => x | -| arrays.js:95:27:95:27 | [SimpleParameter] x | semmle.label | [SimpleParameter] x | -| arrays.js:95:33:95:33 | [VarRef] x | semmle.label | [VarRef] x | | arrays.js:96:3:96:6 | [VarRef] sink | semmle.label | [VarRef] sink | -| arrays.js:96:3:96:37 | [CallExpr] sink([" ... > !!x)) | semmle.label | [CallExpr] sink([" ... > !!x)) | -| arrays.js:96:3:96:38 | [ExprStmt] sink([" ... !!x)); | semmle.label | [ExprStmt] sink([" ... !!x)); | +| arrays.js:96:3:96:41 | [CallExpr] sink([" ... .pop()) | semmle.label | [CallExpr] sink([" ... .pop()) | +| arrays.js:96:3:96:42 | [ExprStmt] sink([" ... pop()); | semmle.label | [ExprStmt] sink([" ... pop()); | | arrays.js:96:8:96:17 | [ArrayExpr] ["source"] | semmle.label | [ArrayExpr] ["source"] | | arrays.js:96:8:96:24 | [DotExpr] ["source"].filter | semmle.label | [DotExpr] ["source"].filter | -| arrays.js:96:8:96:36 | [MethodCallExpr] ["sourc ... => !!x) | semmle.label | [MethodCallExpr] ["sourc ... => !!x) | +| arrays.js:96:8:96:34 | [MethodCallExpr] ["sourc ... ) => x) | semmle.label | [MethodCallExpr] ["sourc ... ) => x) | +| arrays.js:96:8:96:38 | [DotExpr] ["sourc ... x).pop | semmle.label | [DotExpr] ["sourc ... x).pop | +| arrays.js:96:8:96:40 | [MethodCallExpr] ["sourc ... ).pop() | semmle.label | [MethodCallExpr] ["sourc ... ).pop() | | arrays.js:96:9:96:16 | [Literal] "source" | semmle.label | [Literal] "source" | | arrays.js:96:19:96:24 | [Label] filter | semmle.label | [Label] filter | -| arrays.js:96:26:96:35 | [ArrowFunctionExpr] (x) => !!x | semmle.label | [ArrowFunctionExpr] (x) => !!x | +| arrays.js:96:26:96:33 | [ArrowFunctionExpr] (x) => x | semmle.label | [ArrowFunctionExpr] (x) => x | | arrays.js:96:27:96:27 | [SimpleParameter] x | semmle.label | [SimpleParameter] x | -| arrays.js:96:33:96:35 | [UnaryExpr] !!x | semmle.label | [UnaryExpr] !!x | -| arrays.js:96:34:96:35 | [UnaryExpr] !x | semmle.label | [UnaryExpr] !x | -| arrays.js:96:35:96:35 | [VarRef] x | semmle.label | [VarRef] x | +| arrays.js:96:33:96:33 | [VarRef] x | semmle.label | [VarRef] x | +| arrays.js:96:36:96:38 | [Label] pop | semmle.label | [Label] pop | +| arrays.js:97:3:97:6 | [VarRef] sink | semmle.label | [VarRef] sink | +| arrays.js:97:3:97:43 | [CallExpr] sink([" ... .pop()) | semmle.label | [CallExpr] sink([" ... .pop()) | +| arrays.js:97:3:97:44 | [ExprStmt] sink([" ... pop()); | semmle.label | [ExprStmt] sink([" ... pop()); | +| arrays.js:97:8:97:17 | [ArrayExpr] ["source"] | semmle.label | [ArrayExpr] ["source"] | +| arrays.js:97:8:97:24 | [DotExpr] ["source"].filter | semmle.label | [DotExpr] ["source"].filter | +| arrays.js:97:8:97:36 | [MethodCallExpr] ["sourc ... => !!x) | semmle.label | [MethodCallExpr] ["sourc ... => !!x) | +| arrays.js:97:8:97:40 | [DotExpr] ["sourc ... !x).pop | semmle.label | [DotExpr] ["sourc ... !x).pop | +| arrays.js:97:8:97:42 | [MethodCallExpr] ["sourc ... ).pop() | semmle.label | [MethodCallExpr] ["sourc ... ).pop() | +| arrays.js:97:9:97:16 | [Literal] "source" | semmle.label | [Literal] "source" | +| arrays.js:97:19:97:24 | [Label] filter | semmle.label | [Label] filter | +| arrays.js:97:26:97:35 | [ArrowFunctionExpr] (x) => !!x | semmle.label | [ArrowFunctionExpr] (x) => !!x | +| arrays.js:97:27:97:27 | [SimpleParameter] x | semmle.label | [SimpleParameter] x | +| arrays.js:97:33:97:35 | [UnaryExpr] !!x | semmle.label | [UnaryExpr] !!x | +| arrays.js:97:34:97:35 | [UnaryExpr] !x | semmle.label | [UnaryExpr] !x | +| arrays.js:97:35:97:35 | [VarRef] x | semmle.label | [VarRef] x | +| arrays.js:97:38:97:40 | [Label] pop | semmle.label | [Label] pop | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | | file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | | file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | | file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | @@ -476,108 +488,110 @@ nodes | file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | | file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | edges -| arrays.js:1:1:97:2 | [ParExpr] (functi ... T OK }) | arrays.js:1:2:97:1 | [FunctionExpr] functio ... OT OK } | semmle.label | 1 | -| arrays.js:1:1:97:2 | [ParExpr] (functi ... T OK }) | arrays.js:1:2:97:1 | [FunctionExpr] functio ... OT OK } | semmle.order | 1 | -| arrays.js:1:1:97:3 | [ExprStmt] (functi ... OK }); | arrays.js:1:1:97:2 | [ParExpr] (functi ... T OK }) | semmle.label | 1 | -| arrays.js:1:1:97:3 | [ExprStmt] (functi ... OK }); | arrays.js:1:1:97:2 | [ParExpr] (functi ... T OK }) | semmle.order | 1 | -| arrays.js:1:2:97:1 | [FunctionExpr] functio ... OT OK } | arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | semmle.label | 5 | -| arrays.js:1:2:97:1 | [FunctionExpr] functio ... OT OK } | arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | semmle.order | 5 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.label | 1 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.order | 1 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.label | 2 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.order | 2 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.label | 3 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.order | 3 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.label | 4 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.order | 4 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.label | 5 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.order | 5 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.label | 6 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.order | 6 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.label | 7 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.order | 7 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.label | 8 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.order | 8 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.label | 9 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.order | 9 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.label | 10 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.order | 10 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.label | 11 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.order | 11 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.label | 12 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.order | 12 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.label | 13 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.order | 13 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.label | 14 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.order | 14 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.label | 15 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.order | 15 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.label | 16 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.order | 16 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.label | 17 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.order | 17 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:32:3:32:24 | [DeclStmt] var arr4_variant = ... | semmle.label | 18 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:32:3:32:24 | [DeclStmt] var arr4_variant = ... | semmle.order | 18 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:33:3:33:46 | [ExprStmt] arr4_va ... urce"); | semmle.label | 19 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:33:3:33:46 | [ExprStmt] arr4_va ... urce"); | semmle.order | 19 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:34:3:34:21 | [ExprStmt] arr4_variant.pop(); | semmle.label | 20 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:34:3:34:21 | [ExprStmt] arr4_variant.pop(); | semmle.order | 20 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:35:3:35:27 | [ExprStmt] sink(ar ... pop()); | semmle.label | 21 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:35:3:35:27 | [ExprStmt] sink(ar ... pop()); | semmle.order | 21 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:37:3:37:23 | [DeclStmt] var arr4_spread = ... | semmle.label | 22 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:37:3:37:23 | [DeclStmt] var arr4_spread = ... | semmle.order | 22 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:38:3:38:35 | [ExprStmt] arr4_sp ... ..arr); | semmle.label | 23 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:38:3:38:35 | [ExprStmt] arr4_sp ... ..arr); | semmle.order | 23 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:39:3:39:26 | [ExprStmt] sink(ar ... pop()); | semmle.label | 24 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:39:3:39:26 | [ExprStmt] sink(ar ... pop()); | semmle.order | 24 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:41:3:41:29 | [DeclStmt] var arr5 = ... | semmle.label | 25 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:41:3:41:29 | [DeclStmt] var arr5 = ... | semmle.order | 25 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:42:3:42:19 | [ExprStmt] sink(arr5.pop()); | semmle.label | 26 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:42:3:42:19 | [ExprStmt] sink(arr5.pop()); | semmle.order | 26 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:44:3:44:28 | [ExprStmt] sink(ar ... pop()); | semmle.label | 27 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:44:3:44:28 | [ExprStmt] sink(ar ... pop()); | semmle.order | 27 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:46:3:46:16 | [DeclStmt] var arr6 = ... | semmle.label | 28 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:46:3:46:16 | [DeclStmt] var arr6 = ... | semmle.order | 28 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:47:3:49:3 | [ForStmt] for (va ... i]; } | semmle.label | 29 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:47:3:49:3 | [ForStmt] for (va ... i]; } | semmle.order | 29 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:50:3:50:19 | [ExprStmt] sink(arr6.pop()); | semmle.label | 30 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:50:3:50:19 | [ExprStmt] sink(arr6.pop()); | semmle.order | 30 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:53:3:56:5 | [ExprStmt] ["sourc ... . }); | semmle.label | 31 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:53:3:56:5 | [ExprStmt] ["sourc ... . }); | semmle.order | 31 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:58:3:58:15 | [ExprStmt] sink(arr[0]); | semmle.label | 32 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:58:3:58:15 | [ExprStmt] sink(arr[0]); | semmle.order | 32 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:60:3:62:3 | [ForOfStmt] for (co ... OK } | semmle.label | 33 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:60:3:62:3 | [ForOfStmt] for (co ... OK } | semmle.order | 33 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:64:3:66:3 | [ForOfStmt] for (co ... OK } | semmle.label | 34 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:64:3:66:3 | [ForOfStmt] for (co ... OK } | semmle.order | 34 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:68:3:70:3 | [ForOfStmt] for (co ... OK } | semmle.label | 35 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:68:3:70:3 | [ForOfStmt] for (co ... OK } | semmle.order | 35 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:72:3:72:16 | [DeclStmt] var arr7 = ... | semmle.label | 36 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:72:3:72:16 | [DeclStmt] var arr7 = ... | semmle.order | 36 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:73:3:73:20 | [ExprStmt] arr7.push(...arr); | semmle.label | 37 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:73:3:73:20 | [ExprStmt] arr7.push(...arr); | semmle.order | 37 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:74:3:76:3 | [ForOfStmt] for (co ... OK } | semmle.label | 38 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:74:3:76:3 | [ForOfStmt] for (co ... OK } | semmle.order | 38 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:78:3:78:42 | [DeclStmt] const arrayFrom = ... | semmle.label | 39 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:78:3:78:42 | [DeclStmt] const arrayFrom = ... | semmle.order | 39 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:79:3:81:3 | [ForOfStmt] for (co ... OK } | semmle.label | 40 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:79:3:81:3 | [ForOfStmt] for (co ... OK } | semmle.order | 40 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:83:3:83:31 | [ExprStmt] sink(ar ... back)); | semmle.label | 41 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:83:3:83:31 | [ExprStmt] sink(ar ... back)); | semmle.order | 41 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:85:3:85:42 | [DeclStmt] const arrayFind = ... | semmle.label | 42 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:85:3:85:42 | [DeclStmt] const arrayFind = ... | semmle.order | 42 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:86:3:86:37 | [ExprStmt] sink(ar ... back)); | semmle.label | 43 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:86:3:86:37 | [ExprStmt] sink(ar ... back)); | semmle.order | 43 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:88:3:88:31 | [DeclStmt] const uniq = ... | semmle.label | 44 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:88:3:88:31 | [DeclStmt] const uniq = ... | semmle.order | 44 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:89:3:91:3 | [ForOfStmt] for (co ... OK } | semmle.label | 45 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:89:3:91:3 | [ForOfStmt] for (co ... OK } | semmle.order | 45 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:93:3:93:19 | [ExprStmt] sink(arr.at(-1)); | semmle.label | 46 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:93:3:93:19 | [ExprStmt] sink(arr.at(-1)); | semmle.order | 46 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:95:3:95:36 | [ExprStmt] sink([" ... => x)); | semmle.label | 47 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:95:3:95:36 | [ExprStmt] sink([" ... => x)); | semmle.order | 47 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:96:3:96:38 | [ExprStmt] sink([" ... !!x)); | semmle.label | 48 | -| arrays.js:1:14:97:1 | [BlockStmt] { let ... OT OK } | arrays.js:96:3:96:38 | [ExprStmt] sink([" ... !!x)); | semmle.order | 48 | +| arrays.js:1:1:99:2 | [ParExpr] (functi ... OK }) | arrays.js:1:2:99:1 | [FunctionExpr] functio ... T OK } | semmle.label | 1 | +| arrays.js:1:1:99:2 | [ParExpr] (functi ... OK }) | arrays.js:1:2:99:1 | [FunctionExpr] functio ... T OK } | semmle.order | 1 | +| arrays.js:1:1:99:3 | [ExprStmt] (functi ... OK }); | arrays.js:1:1:99:2 | [ParExpr] (functi ... OK }) | semmle.label | 1 | +| arrays.js:1:1:99:3 | [ExprStmt] (functi ... OK }); | arrays.js:1:1:99:2 | [ParExpr] (functi ... OK }) | semmle.order | 1 | +| arrays.js:1:2:99:1 | [FunctionExpr] functio ... T OK } | arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | semmle.label | 5 | +| arrays.js:1:2:99:1 | [FunctionExpr] functio ... T OK } | arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | semmle.order | 5 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.label | 1 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.order | 1 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.label | 2 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.order | 2 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.label | 3 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.order | 3 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.label | 4 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.order | 4 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.label | 5 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.order | 5 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.label | 6 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.order | 6 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.label | 7 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.order | 7 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.label | 8 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.order | 8 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.label | 9 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.order | 9 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.label | 10 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.order | 10 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.label | 11 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.order | 11 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.label | 12 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.order | 12 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.label | 13 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.order | 13 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.label | 14 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.order | 14 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.label | 15 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.order | 15 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.label | 16 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.order | 16 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.label | 17 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.order | 17 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:32:3:32:24 | [DeclStmt] var arr4_variant = ... | semmle.label | 18 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:32:3:32:24 | [DeclStmt] var arr4_variant = ... | semmle.order | 18 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:33:3:33:46 | [ExprStmt] arr4_va ... urce"); | semmle.label | 19 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:33:3:33:46 | [ExprStmt] arr4_va ... urce"); | semmle.order | 19 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:34:3:34:21 | [ExprStmt] arr4_variant.pop(); | semmle.label | 20 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:34:3:34:21 | [ExprStmt] arr4_variant.pop(); | semmle.order | 20 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:35:3:35:27 | [ExprStmt] sink(ar ... pop()); | semmle.label | 21 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:35:3:35:27 | [ExprStmt] sink(ar ... pop()); | semmle.order | 21 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:37:3:37:23 | [DeclStmt] var arr4_spread = ... | semmle.label | 22 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:37:3:37:23 | [DeclStmt] var arr4_spread = ... | semmle.order | 22 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:38:3:38:35 | [ExprStmt] arr4_sp ... ..arr); | semmle.label | 23 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:38:3:38:35 | [ExprStmt] arr4_sp ... ..arr); | semmle.order | 23 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:39:3:39:26 | [ExprStmt] sink(ar ... pop()); | semmle.label | 24 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:39:3:39:26 | [ExprStmt] sink(ar ... pop()); | semmle.order | 24 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:41:3:41:29 | [DeclStmt] var arr5 = ... | semmle.label | 25 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:41:3:41:29 | [DeclStmt] var arr5 = ... | semmle.order | 25 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:42:3:42:19 | [ExprStmt] sink(arr5.pop()); | semmle.label | 26 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:42:3:42:19 | [ExprStmt] sink(arr5.pop()); | semmle.order | 26 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:44:3:44:28 | [ExprStmt] sink(ar ... pop()); | semmle.label | 27 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:44:3:44:28 | [ExprStmt] sink(ar ... pop()); | semmle.order | 27 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:46:3:46:16 | [DeclStmt] var arr6 = ... | semmle.label | 28 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:46:3:46:16 | [DeclStmt] var arr6 = ... | semmle.order | 28 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:47:3:49:3 | [ForStmt] for (va ... i]; } | semmle.label | 29 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:47:3:49:3 | [ForStmt] for (va ... i]; } | semmle.order | 29 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:50:3:50:19 | [ExprStmt] sink(arr6.pop()); | semmle.label | 30 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:50:3:50:19 | [ExprStmt] sink(arr6.pop()); | semmle.order | 30 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:53:3:56:5 | [ExprStmt] ["sourc ... . }); | semmle.label | 31 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:53:3:56:5 | [ExprStmt] ["sourc ... . }); | semmle.order | 31 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:58:3:58:15 | [ExprStmt] sink(arr[0]); | semmle.label | 32 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:58:3:58:15 | [ExprStmt] sink(arr[0]); | semmle.order | 32 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:60:3:62:3 | [ForOfStmt] for (co ... OK } | semmle.label | 33 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:60:3:62:3 | [ForOfStmt] for (co ... OK } | semmle.order | 33 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:64:3:66:3 | [ForOfStmt] for (co ... OK } | semmle.label | 34 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:64:3:66:3 | [ForOfStmt] for (co ... OK } | semmle.order | 34 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:68:3:70:3 | [ForOfStmt] for (co ... OK } | semmle.label | 35 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:68:3:70:3 | [ForOfStmt] for (co ... OK } | semmle.order | 35 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:72:3:72:16 | [DeclStmt] var arr7 = ... | semmle.label | 36 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:72:3:72:16 | [DeclStmt] var arr7 = ... | semmle.order | 36 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:73:3:73:20 | [ExprStmt] arr7.push(...arr); | semmle.label | 37 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:73:3:73:20 | [ExprStmt] arr7.push(...arr); | semmle.order | 37 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:74:3:76:3 | [ForOfStmt] for (co ... OK } | semmle.label | 38 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:74:3:76:3 | [ForOfStmt] for (co ... OK } | semmle.order | 38 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:78:3:78:42 | [DeclStmt] const arrayFrom = ... | semmle.label | 39 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:78:3:78:42 | [DeclStmt] const arrayFrom = ... | semmle.order | 39 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:79:3:81:3 | [ForOfStmt] for (co ... OK } | semmle.label | 40 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:79:3:81:3 | [ForOfStmt] for (co ... OK } | semmle.order | 40 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:83:3:83:31 | [ExprStmt] sink(ar ... back)); | semmle.label | 41 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:83:3:83:31 | [ExprStmt] sink(ar ... back)); | semmle.order | 41 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:85:3:85:42 | [DeclStmt] const arrayFind = ... | semmle.label | 42 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:85:3:85:42 | [DeclStmt] const arrayFind = ... | semmle.order | 42 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:86:3:86:37 | [ExprStmt] sink(ar ... back)); | semmle.label | 43 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:86:3:86:37 | [ExprStmt] sink(ar ... back)); | semmle.order | 43 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:88:3:88:31 | [DeclStmt] const uniq = ... | semmle.label | 44 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:88:3:88:31 | [DeclStmt] const uniq = ... | semmle.order | 44 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:89:3:91:3 | [ForOfStmt] for (co ... OK } | semmle.label | 45 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:89:3:91:3 | [ForOfStmt] for (co ... OK } | semmle.order | 45 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:93:3:93:19 | [ExprStmt] sink(arr.at(-1)); | semmle.label | 46 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:93:3:93:19 | [ExprStmt] sink(arr.at(-1)); | semmle.order | 46 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:95:3:95:19 | [ExprStmt] sink(["source"]); | semmle.label | 47 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:95:3:95:19 | [ExprStmt] sink(["source"]); | semmle.order | 47 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:96:3:96:42 | [ExprStmt] sink([" ... pop()); | semmle.label | 48 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:96:3:96:42 | [ExprStmt] sink([" ... pop()); | semmle.order | 48 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:97:3:97:44 | [ExprStmt] sink([" ... pop()); | semmle.label | 49 | +| arrays.js:1:14:99:1 | [BlockStmt] { let ... T OK } | arrays.js:97:3:97:44 | [ExprStmt] sink([" ... pop()); | semmle.order | 49 | | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | semmle.label | 1 | | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | semmle.order | 1 | | arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | arrays.js:2:7:2:12 | [VarDecl] source | semmle.label | 1 | @@ -1244,50 +1258,70 @@ edges | arrays.js:93:8:93:17 | [MethodCallExpr] arr.at(-1) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | | arrays.js:93:15:93:16 | [UnaryExpr] -1 | arrays.js:93:16:93:16 | [Literal] 1 | semmle.label | 1 | | arrays.js:93:15:93:16 | [UnaryExpr] -1 | arrays.js:93:16:93:16 | [Literal] 1 | semmle.order | 1 | -| arrays.js:95:3:95:35 | [CallExpr] sink([" ... => x)) | arrays.js:95:3:95:6 | [VarRef] sink | semmle.label | 0 | -| arrays.js:95:3:95:35 | [CallExpr] sink([" ... => x)) | arrays.js:95:3:95:6 | [VarRef] sink | semmle.order | 0 | -| arrays.js:95:3:95:35 | [CallExpr] sink([" ... => x)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | -| arrays.js:95:3:95:35 | [CallExpr] sink([" ... => x)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | -| arrays.js:95:3:95:36 | [ExprStmt] sink([" ... => x)); | arrays.js:95:3:95:35 | [CallExpr] sink([" ... => x)) | semmle.label | 1 | -| arrays.js:95:3:95:36 | [ExprStmt] sink([" ... => x)); | arrays.js:95:3:95:35 | [CallExpr] sink([" ... => x)) | semmle.order | 1 | +| arrays.js:95:3:95:18 | [CallExpr] sink(["source"]) | arrays.js:95:3:95:6 | [VarRef] sink | semmle.label | 0 | +| arrays.js:95:3:95:18 | [CallExpr] sink(["source"]) | arrays.js:95:3:95:6 | [VarRef] sink | semmle.order | 0 | +| arrays.js:95:3:95:18 | [CallExpr] sink(["source"]) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:95:3:95:18 | [CallExpr] sink(["source"]) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:95:3:95:19 | [ExprStmt] sink(["source"]); | arrays.js:95:3:95:18 | [CallExpr] sink(["source"]) | semmle.label | 1 | +| arrays.js:95:3:95:19 | [ExprStmt] sink(["source"]); | arrays.js:95:3:95:18 | [CallExpr] sink(["source"]) | semmle.order | 1 | | arrays.js:95:8:95:17 | [ArrayExpr] ["source"] | arrays.js:95:9:95:16 | [Literal] "source" | semmle.label | 1 | | arrays.js:95:8:95:17 | [ArrayExpr] ["source"] | arrays.js:95:9:95:16 | [Literal] "source" | semmle.order | 1 | -| arrays.js:95:8:95:24 | [DotExpr] ["source"].filter | arrays.js:95:8:95:17 | [ArrayExpr] ["source"] | semmle.label | 1 | -| arrays.js:95:8:95:24 | [DotExpr] ["source"].filter | arrays.js:95:8:95:17 | [ArrayExpr] ["source"] | semmle.order | 1 | -| arrays.js:95:8:95:24 | [DotExpr] ["source"].filter | arrays.js:95:19:95:24 | [Label] filter | semmle.label | 2 | -| arrays.js:95:8:95:24 | [DotExpr] ["source"].filter | arrays.js:95:19:95:24 | [Label] filter | semmle.order | 2 | -| arrays.js:95:8:95:34 | [MethodCallExpr] ["sourc ... ) => x) | arrays.js:95:8:95:24 | [DotExpr] ["source"].filter | semmle.label | 0 | -| arrays.js:95:8:95:34 | [MethodCallExpr] ["sourc ... ) => x) | arrays.js:95:8:95:24 | [DotExpr] ["source"].filter | semmle.order | 0 | -| arrays.js:95:8:95:34 | [MethodCallExpr] ["sourc ... ) => x) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | -| arrays.js:95:8:95:34 | [MethodCallExpr] ["sourc ... ) => x) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | -| arrays.js:95:26:95:33 | [ArrowFunctionExpr] (x) => x | arrays.js:95:33:95:33 | [VarRef] x | semmle.label | 5 | -| arrays.js:95:26:95:33 | [ArrowFunctionExpr] (x) => x | arrays.js:95:33:95:33 | [VarRef] x | semmle.order | 5 | -| arrays.js:95:26:95:33 | [ArrowFunctionExpr] (x) => x | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | -| arrays.js:95:26:95:33 | [ArrowFunctionExpr] (x) => x | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | -| arrays.js:96:3:96:37 | [CallExpr] sink([" ... > !!x)) | arrays.js:96:3:96:6 | [VarRef] sink | semmle.label | 0 | -| arrays.js:96:3:96:37 | [CallExpr] sink([" ... > !!x)) | arrays.js:96:3:96:6 | [VarRef] sink | semmle.order | 0 | -| arrays.js:96:3:96:37 | [CallExpr] sink([" ... > !!x)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | -| arrays.js:96:3:96:37 | [CallExpr] sink([" ... > !!x)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | -| arrays.js:96:3:96:38 | [ExprStmt] sink([" ... !!x)); | arrays.js:96:3:96:37 | [CallExpr] sink([" ... > !!x)) | semmle.label | 1 | -| arrays.js:96:3:96:38 | [ExprStmt] sink([" ... !!x)); | arrays.js:96:3:96:37 | [CallExpr] sink([" ... > !!x)) | semmle.order | 1 | +| arrays.js:96:3:96:41 | [CallExpr] sink([" ... .pop()) | arrays.js:96:3:96:6 | [VarRef] sink | semmle.label | 0 | +| arrays.js:96:3:96:41 | [CallExpr] sink([" ... .pop()) | arrays.js:96:3:96:6 | [VarRef] sink | semmle.order | 0 | +| arrays.js:96:3:96:41 | [CallExpr] sink([" ... .pop()) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:96:3:96:41 | [CallExpr] sink([" ... .pop()) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:96:3:96:42 | [ExprStmt] sink([" ... pop()); | arrays.js:96:3:96:41 | [CallExpr] sink([" ... .pop()) | semmle.label | 1 | +| arrays.js:96:3:96:42 | [ExprStmt] sink([" ... pop()); | arrays.js:96:3:96:41 | [CallExpr] sink([" ... .pop()) | semmle.order | 1 | | arrays.js:96:8:96:17 | [ArrayExpr] ["source"] | arrays.js:96:9:96:16 | [Literal] "source" | semmle.label | 1 | | arrays.js:96:8:96:17 | [ArrayExpr] ["source"] | arrays.js:96:9:96:16 | [Literal] "source" | semmle.order | 1 | | arrays.js:96:8:96:24 | [DotExpr] ["source"].filter | arrays.js:96:8:96:17 | [ArrayExpr] ["source"] | semmle.label | 1 | | arrays.js:96:8:96:24 | [DotExpr] ["source"].filter | arrays.js:96:8:96:17 | [ArrayExpr] ["source"] | semmle.order | 1 | | arrays.js:96:8:96:24 | [DotExpr] ["source"].filter | arrays.js:96:19:96:24 | [Label] filter | semmle.label | 2 | | arrays.js:96:8:96:24 | [DotExpr] ["source"].filter | arrays.js:96:19:96:24 | [Label] filter | semmle.order | 2 | -| arrays.js:96:8:96:36 | [MethodCallExpr] ["sourc ... => !!x) | arrays.js:96:8:96:24 | [DotExpr] ["source"].filter | semmle.label | 0 | -| arrays.js:96:8:96:36 | [MethodCallExpr] ["sourc ... => !!x) | arrays.js:96:8:96:24 | [DotExpr] ["source"].filter | semmle.order | 0 | -| arrays.js:96:8:96:36 | [MethodCallExpr] ["sourc ... => !!x) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | -| arrays.js:96:8:96:36 | [MethodCallExpr] ["sourc ... => !!x) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | -| arrays.js:96:26:96:35 | [ArrowFunctionExpr] (x) => !!x | arrays.js:96:33:96:35 | [UnaryExpr] !!x | semmle.label | 5 | -| arrays.js:96:26:96:35 | [ArrowFunctionExpr] (x) => !!x | arrays.js:96:33:96:35 | [UnaryExpr] !!x | semmle.order | 5 | -| arrays.js:96:26:96:35 | [ArrowFunctionExpr] (x) => !!x | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | -| arrays.js:96:26:96:35 | [ArrowFunctionExpr] (x) => !!x | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | -| arrays.js:96:33:96:35 | [UnaryExpr] !!x | arrays.js:96:34:96:35 | [UnaryExpr] !x | semmle.label | 1 | -| arrays.js:96:33:96:35 | [UnaryExpr] !!x | arrays.js:96:34:96:35 | [UnaryExpr] !x | semmle.order | 1 | -| arrays.js:96:34:96:35 | [UnaryExpr] !x | arrays.js:96:35:96:35 | [VarRef] x | semmle.label | 1 | -| arrays.js:96:34:96:35 | [UnaryExpr] !x | arrays.js:96:35:96:35 | [VarRef] x | semmle.order | 1 | +| arrays.js:96:8:96:34 | [MethodCallExpr] ["sourc ... ) => x) | arrays.js:96:8:96:24 | [DotExpr] ["source"].filter | semmle.label | 0 | +| arrays.js:96:8:96:34 | [MethodCallExpr] ["sourc ... ) => x) | arrays.js:96:8:96:24 | [DotExpr] ["source"].filter | semmle.order | 0 | +| arrays.js:96:8:96:34 | [MethodCallExpr] ["sourc ... ) => x) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:96:8:96:34 | [MethodCallExpr] ["sourc ... ) => x) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:96:8:96:38 | [DotExpr] ["sourc ... x).pop | arrays.js:96:8:96:34 | [MethodCallExpr] ["sourc ... ) => x) | semmle.label | 1 | +| arrays.js:96:8:96:38 | [DotExpr] ["sourc ... x).pop | arrays.js:96:8:96:34 | [MethodCallExpr] ["sourc ... ) => x) | semmle.order | 1 | +| arrays.js:96:8:96:38 | [DotExpr] ["sourc ... x).pop | arrays.js:96:36:96:38 | [Label] pop | semmle.label | 2 | +| arrays.js:96:8:96:38 | [DotExpr] ["sourc ... x).pop | arrays.js:96:36:96:38 | [Label] pop | semmle.order | 2 | +| arrays.js:96:8:96:40 | [MethodCallExpr] ["sourc ... ).pop() | arrays.js:96:8:96:38 | [DotExpr] ["sourc ... x).pop | semmle.label | 0 | +| arrays.js:96:8:96:40 | [MethodCallExpr] ["sourc ... ).pop() | arrays.js:96:8:96:38 | [DotExpr] ["sourc ... x).pop | semmle.order | 0 | +| arrays.js:96:26:96:33 | [ArrowFunctionExpr] (x) => x | arrays.js:96:33:96:33 | [VarRef] x | semmle.label | 5 | +| arrays.js:96:26:96:33 | [ArrowFunctionExpr] (x) => x | arrays.js:96:33:96:33 | [VarRef] x | semmle.order | 5 | +| arrays.js:96:26:96:33 | [ArrowFunctionExpr] (x) => x | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| arrays.js:96:26:96:33 | [ArrowFunctionExpr] (x) => x | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| arrays.js:97:3:97:43 | [CallExpr] sink([" ... .pop()) | arrays.js:97:3:97:6 | [VarRef] sink | semmle.label | 0 | +| arrays.js:97:3:97:43 | [CallExpr] sink([" ... .pop()) | arrays.js:97:3:97:6 | [VarRef] sink | semmle.order | 0 | +| arrays.js:97:3:97:43 | [CallExpr] sink([" ... .pop()) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:97:3:97:43 | [CallExpr] sink([" ... .pop()) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:97:3:97:44 | [ExprStmt] sink([" ... pop()); | arrays.js:97:3:97:43 | [CallExpr] sink([" ... .pop()) | semmle.label | 1 | +| arrays.js:97:3:97:44 | [ExprStmt] sink([" ... pop()); | arrays.js:97:3:97:43 | [CallExpr] sink([" ... .pop()) | semmle.order | 1 | +| arrays.js:97:8:97:17 | [ArrayExpr] ["source"] | arrays.js:97:9:97:16 | [Literal] "source" | semmle.label | 1 | +| arrays.js:97:8:97:17 | [ArrayExpr] ["source"] | arrays.js:97:9:97:16 | [Literal] "source" | semmle.order | 1 | +| arrays.js:97:8:97:24 | [DotExpr] ["source"].filter | arrays.js:97:8:97:17 | [ArrayExpr] ["source"] | semmle.label | 1 | +| arrays.js:97:8:97:24 | [DotExpr] ["source"].filter | arrays.js:97:8:97:17 | [ArrayExpr] ["source"] | semmle.order | 1 | +| arrays.js:97:8:97:24 | [DotExpr] ["source"].filter | arrays.js:97:19:97:24 | [Label] filter | semmle.label | 2 | +| arrays.js:97:8:97:24 | [DotExpr] ["source"].filter | arrays.js:97:19:97:24 | [Label] filter | semmle.order | 2 | +| arrays.js:97:8:97:36 | [MethodCallExpr] ["sourc ... => !!x) | arrays.js:97:8:97:24 | [DotExpr] ["source"].filter | semmle.label | 0 | +| arrays.js:97:8:97:36 | [MethodCallExpr] ["sourc ... => !!x) | arrays.js:97:8:97:24 | [DotExpr] ["source"].filter | semmle.order | 0 | +| arrays.js:97:8:97:36 | [MethodCallExpr] ["sourc ... => !!x) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:97:8:97:36 | [MethodCallExpr] ["sourc ... => !!x) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:97:8:97:40 | [DotExpr] ["sourc ... !x).pop | arrays.js:97:8:97:36 | [MethodCallExpr] ["sourc ... => !!x) | semmle.label | 1 | +| arrays.js:97:8:97:40 | [DotExpr] ["sourc ... !x).pop | arrays.js:97:8:97:36 | [MethodCallExpr] ["sourc ... => !!x) | semmle.order | 1 | +| arrays.js:97:8:97:40 | [DotExpr] ["sourc ... !x).pop | arrays.js:97:38:97:40 | [Label] pop | semmle.label | 2 | +| arrays.js:97:8:97:40 | [DotExpr] ["sourc ... !x).pop | arrays.js:97:38:97:40 | [Label] pop | semmle.order | 2 | +| arrays.js:97:8:97:42 | [MethodCallExpr] ["sourc ... ).pop() | arrays.js:97:8:97:40 | [DotExpr] ["sourc ... !x).pop | semmle.label | 0 | +| arrays.js:97:8:97:42 | [MethodCallExpr] ["sourc ... ).pop() | arrays.js:97:8:97:40 | [DotExpr] ["sourc ... !x).pop | semmle.order | 0 | +| arrays.js:97:26:97:35 | [ArrowFunctionExpr] (x) => !!x | arrays.js:97:33:97:35 | [UnaryExpr] !!x | semmle.label | 5 | +| arrays.js:97:26:97:35 | [ArrowFunctionExpr] (x) => !!x | arrays.js:97:33:97:35 | [UnaryExpr] !!x | semmle.order | 5 | +| arrays.js:97:26:97:35 | [ArrowFunctionExpr] (x) => !!x | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| arrays.js:97:26:97:35 | [ArrowFunctionExpr] (x) => !!x | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| arrays.js:97:33:97:35 | [UnaryExpr] !!x | arrays.js:97:34:97:35 | [UnaryExpr] !x | semmle.label | 1 | +| arrays.js:97:33:97:35 | [UnaryExpr] !!x | arrays.js:97:34:97:35 | [UnaryExpr] !x | semmle.order | 1 | +| arrays.js:97:34:97:35 | [UnaryExpr] !x | arrays.js:97:35:97:35 | [VarRef] x | semmle.label | 1 | +| arrays.js:97:34:97:35 | [UnaryExpr] !x | arrays.js:97:35:97:35 | [VarRef] x | semmle.order | 1 | | file://:0:0:0:0 | (Arguments) | arrays.js:5:8:5:14 | [DotExpr] obj.foo | semmle.label | 0 | | file://:0:0:0:0 | (Arguments) | arrays.js:5:8:5:14 | [DotExpr] obj.foo | semmle.order | 0 | | file://:0:0:0:0 | (Arguments) | arrays.js:8:12:8:17 | [VarRef] source | semmle.label | 0 | @@ -1398,14 +1432,16 @@ edges | file://:0:0:0:0 | (Arguments) | arrays.js:93:8:93:17 | [MethodCallExpr] arr.at(-1) | semmle.order | 0 | | file://:0:0:0:0 | (Arguments) | arrays.js:93:15:93:16 | [UnaryExpr] -1 | semmle.label | 0 | | file://:0:0:0:0 | (Arguments) | arrays.js:93:15:93:16 | [UnaryExpr] -1 | semmle.order | 0 | -| file://:0:0:0:0 | (Arguments) | arrays.js:95:8:95:34 | [MethodCallExpr] ["sourc ... ) => x) | semmle.label | 0 | -| file://:0:0:0:0 | (Arguments) | arrays.js:95:8:95:34 | [MethodCallExpr] ["sourc ... ) => x) | semmle.order | 0 | -| file://:0:0:0:0 | (Arguments) | arrays.js:95:26:95:33 | [ArrowFunctionExpr] (x) => x | semmle.label | 0 | -| file://:0:0:0:0 | (Arguments) | arrays.js:95:26:95:33 | [ArrowFunctionExpr] (x) => x | semmle.order | 0 | -| file://:0:0:0:0 | (Arguments) | arrays.js:96:8:96:36 | [MethodCallExpr] ["sourc ... => !!x) | semmle.label | 0 | -| file://:0:0:0:0 | (Arguments) | arrays.js:96:8:96:36 | [MethodCallExpr] ["sourc ... => !!x) | semmle.order | 0 | -| file://:0:0:0:0 | (Arguments) | arrays.js:96:26:96:35 | [ArrowFunctionExpr] (x) => !!x | semmle.label | 0 | -| file://:0:0:0:0 | (Arguments) | arrays.js:96:26:96:35 | [ArrowFunctionExpr] (x) => !!x | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:95:8:95:17 | [ArrayExpr] ["source"] | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:95:8:95:17 | [ArrayExpr] ["source"] | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:96:8:96:40 | [MethodCallExpr] ["sourc ... ).pop() | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:96:8:96:40 | [MethodCallExpr] ["sourc ... ).pop() | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:96:26:96:33 | [ArrowFunctionExpr] (x) => x | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:96:26:96:33 | [ArrowFunctionExpr] (x) => x | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:97:8:97:42 | [MethodCallExpr] ["sourc ... ).pop() | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:97:8:97:42 | [MethodCallExpr] ["sourc ... ).pop() | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:97:26:97:35 | [ArrowFunctionExpr] (x) => !!x | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:97:26:97:35 | [ArrowFunctionExpr] (x) => !!x | semmle.order | 0 | | file://:0:0:0:0 | (Parameters) | arrays.js:15:16:15:16 | [SimpleParameter] e | semmle.label | 0 | | file://:0:0:0:0 | (Parameters) | arrays.js:15:16:15:16 | [SimpleParameter] e | semmle.order | 0 | | file://:0:0:0:0 | (Parameters) | arrays.js:16:12:16:12 | [SimpleParameter] e | semmle.label | 0 | @@ -1420,9 +1456,9 @@ edges | file://:0:0:0:0 | (Parameters) | arrays.js:53:26:53:26 | [SimpleParameter] i | semmle.order | 1 | | file://:0:0:0:0 | (Parameters) | arrays.js:53:29:53:31 | [SimpleParameter] ary | semmle.label | 2 | | file://:0:0:0:0 | (Parameters) | arrays.js:53:29:53:31 | [SimpleParameter] ary | semmle.order | 2 | -| file://:0:0:0:0 | (Parameters) | arrays.js:95:27:95:27 | [SimpleParameter] x | semmle.label | 0 | -| file://:0:0:0:0 | (Parameters) | arrays.js:95:27:95:27 | [SimpleParameter] x | semmle.order | 0 | | file://:0:0:0:0 | (Parameters) | arrays.js:96:27:96:27 | [SimpleParameter] x | semmle.label | 0 | | file://:0:0:0:0 | (Parameters) | arrays.js:96:27:96:27 | [SimpleParameter] x | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | arrays.js:97:27:97:27 | [SimpleParameter] x | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | arrays.js:97:27:97:27 | [SimpleParameter] x | semmle.order | 0 | graphProperties | semmle.graphKind | tree | From df42e7c5271e28d08454035dc464a2ec21073ec9 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 19 Aug 2024 12:01:41 +0200 Subject: [PATCH 22/37] JS: Add test showing lack of implicit reads for ArrayElement --- .../TaintTracking/BasicTaintTracking.expected | 3 +++ .../TaintTracking/DataFlowTracking.expected | 2 ++ .../use-use-after-implicit-read.js | 17 +++++++++++++++++ 3 files changed, 22 insertions(+) create mode 100644 javascript/ql/test/library-tests/TaintTracking/use-use-after-implicit-read.js diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index fd2fb8bbc09d..a48580ba6e39 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -32,6 +32,8 @@ legacyDataFlowDifference | object-bypass-sanitizer.js:35:29:35:36 | source() | object-bypass-sanitizer.js:28:10:28:30 | sanitiz ... bj).foo | only flow with OLD data flow library | | promise.js:12:20:12:27 | source() | promise.js:13:8:13:23 | resolver.promise | only flow with OLD data flow library | | sanitizer-guards.js:57:11:57:18 | source() | sanitizer-guards.js:64:8:64:8 | x | only flow with NEW data flow library | +| use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:8:10:8:17 | captured | only flow with OLD data flow library | +| use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:15:10:15:10 | x | only flow with NEW data flow library | consistencyIssue | library-tests/TaintTracking/nested-props.js:20 | expected an alert, but found none | NOT OK - but not found | Consistency | | library-tests/TaintTracking/stringification-read-steps.js:17 | expected an alert, but found none | NOT OK | Consistency | @@ -289,6 +291,7 @@ flow | tst.js:2:13:2:20 | source() | tst.js:48:10:48:22 | new Buffer(x) | | tst.js:2:13:2:20 | source() | tst.js:51:10:51:31 | seriali ... ript(x) | | tst.js:2:13:2:20 | source() | tst.js:54:14:54:19 | unsafe | +| use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:15:10:15:10 | x | | xml.js:5:18:5:25 | source() | xml.js:8:14:8:17 | text | | xml.js:12:17:12:24 | source() | xml.js:13:14:13:19 | result | | xml.js:23:18:23:25 | source() | xml.js:20:14:20:17 | attr | diff --git a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected index 18ff982fa1e9..a90bae109998 100644 --- a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected @@ -24,6 +24,7 @@ legacyDataFlowDifference | sanitizer-guards.js:57:11:57:18 | source() | sanitizer-guards.js:64:8:64:8 | x | only flow with NEW data flow library | | tst.js:2:13:2:20 | source() | tst.js:35:14:35:16 | ary | only flow with NEW data flow library | | tst.js:2:13:2:20 | source() | tst.js:41:14:41:16 | ary | only flow with NEW data flow library | +| use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:15:10:15:10 | x | only flow with NEW data flow library | flow | access-path-sanitizer.js:2:18:2:25 | source() | access-path-sanitizer.js:4:8:4:12 | obj.x | | advanced-callgraph.js:2:13:2:20 | source() | advanced-callgraph.js:6:22:6:22 | v | @@ -181,3 +182,4 @@ flow | tst.js:2:13:2:20 | source() | tst.js:35:14:35:16 | ary | | tst.js:2:13:2:20 | source() | tst.js:41:14:41:16 | ary | | tst.js:2:13:2:20 | source() | tst.js:54:14:54:19 | unsafe | +| use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:15:10:15:10 | x | diff --git a/javascript/ql/test/library-tests/TaintTracking/use-use-after-implicit-read.js b/javascript/ql/test/library-tests/TaintTracking/use-use-after-implicit-read.js new file mode 100644 index 000000000000..43ce5fc99feb --- /dev/null +++ b/javascript/ql/test/library-tests/TaintTracking/use-use-after-implicit-read.js @@ -0,0 +1,17 @@ +import 'dummy'; + +function f(x) { + let captured; + function inner() { captured; captured = "sdf"; } + + captured = [source(), "safe", x]; + sink(captured); // NOT OK [INCONSISTENCY] - no implicit read of ArrayElement + g.apply(undefined, captured); // with use-use flow the output of an implicit read might flow here + + return captured; +} + +function g(x, y) { + sink(x); // NOT OK + sink(y); // OK +} From 371f7ef551b5fcc7e009e50a6f9797d358a8852d Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 19 Aug 2024 14:15:02 +0200 Subject: [PATCH 23/37] JS: Add implicit taint read of array elements --- .../javascript/dataflow/internal/TaintTrackingPrivate.qll | 2 +- .../library-tests/TaintTracking/BasicTaintTracking.expected | 4 +++- .../TaintTracking/use-use-after-implicit-read.js | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll index 9d17da244c5f..69d275a74dce 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll @@ -61,5 +61,5 @@ predicate defaultTaintSanitizer(DataFlow::Node node) { bindingset[node] predicate defaultImplicitTaintRead(DataFlow::Node node, ContentSet c) { exists(node) and - c = ContentSet::promiseValue() + c = [ContentSet::promiseValue(), ContentSet::arrayElement()] } diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index a48580ba6e39..7f249cc675d4 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -32,8 +32,8 @@ legacyDataFlowDifference | object-bypass-sanitizer.js:35:29:35:36 | source() | object-bypass-sanitizer.js:28:10:28:30 | sanitiz ... bj).foo | only flow with OLD data flow library | | promise.js:12:20:12:27 | source() | promise.js:13:8:13:23 | resolver.promise | only flow with OLD data flow library | | sanitizer-guards.js:57:11:57:18 | source() | sanitizer-guards.js:64:8:64:8 | x | only flow with NEW data flow library | -| use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:8:10:8:17 | captured | only flow with OLD data flow library | | use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:15:10:15:10 | x | only flow with NEW data flow library | +| use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:16:10:16:10 | y | only flow with NEW data flow library | consistencyIssue | library-tests/TaintTracking/nested-props.js:20 | expected an alert, but found none | NOT OK - but not found | Consistency | | library-tests/TaintTracking/stringification-read-steps.js:17 | expected an alert, but found none | NOT OK | Consistency | @@ -291,7 +291,9 @@ flow | tst.js:2:13:2:20 | source() | tst.js:48:10:48:22 | new Buffer(x) | | tst.js:2:13:2:20 | source() | tst.js:51:10:51:31 | seriali ... ript(x) | | tst.js:2:13:2:20 | source() | tst.js:54:14:54:19 | unsafe | +| use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:8:10:8:17 | captured | | use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:15:10:15:10 | x | +| use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:16:10:16:10 | y | | xml.js:5:18:5:25 | source() | xml.js:8:14:8:17 | text | | xml.js:12:17:12:24 | source() | xml.js:13:14:13:19 | result | | xml.js:23:18:23:25 | source() | xml.js:20:14:20:17 | attr | diff --git a/javascript/ql/test/library-tests/TaintTracking/use-use-after-implicit-read.js b/javascript/ql/test/library-tests/TaintTracking/use-use-after-implicit-read.js index 43ce5fc99feb..17c11b6a5055 100644 --- a/javascript/ql/test/library-tests/TaintTracking/use-use-after-implicit-read.js +++ b/javascript/ql/test/library-tests/TaintTracking/use-use-after-implicit-read.js @@ -5,7 +5,7 @@ function f(x) { function inner() { captured; captured = "sdf"; } captured = [source(), "safe", x]; - sink(captured); // NOT OK [INCONSISTENCY] - no implicit read of ArrayElement + sink(captured); // NOT OK - implicit read of ArrayElement g.apply(undefined, captured); // with use-use flow the output of an implicit read might flow here return captured; @@ -13,5 +13,5 @@ function f(x) { function g(x, y) { sink(x); // NOT OK - sink(y); // OK + sink(y); // OK [INCONSISTENCY] - implicit read confuses array index } From aa8bd332bf351ae58a5dbe2cf1487bf43d25ceac Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 22 Aug 2024 11:43:29 +0200 Subject: [PATCH 24/37] JS: Add a few more tests --- .../TaintTracking/BasicTaintTracking.expected | 12 ++++++++---- .../TaintTracking/DataFlowTracking.expected | 4 ++++ .../library-tests/TaintTracking/spread.js | 19 ++++++++++++++++++- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 7f249cc675d4..2a1ca5c57f6b 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -32,6 +32,8 @@ legacyDataFlowDifference | object-bypass-sanitizer.js:35:29:35:36 | source() | object-bypass-sanitizer.js:28:10:28:30 | sanitiz ... bj).foo | only flow with OLD data flow library | | promise.js:12:20:12:27 | source() | promise.js:13:8:13:23 | resolver.promise | only flow with OLD data flow library | | sanitizer-guards.js:57:11:57:18 | source() | sanitizer-guards.js:64:8:64:8 | x | only flow with NEW data flow library | +| spread.js:4:15:4:22 | source() | spread.js:18:8:18:8 | y | only flow with NEW data flow library | +| spread.js:4:15:4:22 | source() | spread.js:24:8:24:8 | y | only flow with NEW data flow library | | use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:15:10:15:10 | x | only flow with NEW data flow library | | use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:16:10:16:10 | y | only flow with NEW data flow library | consistencyIssue @@ -250,10 +252,12 @@ flow | sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:93:8:93:8 | x | | sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:98:7:98:7 | x | | sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:104:7:104:7 | x | -| spread.js:2:15:2:22 | source() | spread.js:4:8:4:19 | { ...taint } | -| spread.js:2:15:2:22 | source() | spread.js:5:8:5:43 | { f: 'h ... orld' } | -| spread.js:2:15:2:22 | source() | spread.js:7:8:7:19 | [ ...taint ] | -| spread.js:2:15:2:22 | source() | spread.js:8:8:8:28 | [ 1, 2, ... nt, 3 ] | +| spread.js:4:15:4:22 | source() | spread.js:6:8:6:19 | { ...taint } | +| spread.js:4:15:4:22 | source() | spread.js:7:8:7:43 | { f: 'h ... orld' } | +| spread.js:4:15:4:22 | source() | spread.js:9:8:9:19 | [ ...taint ] | +| spread.js:4:15:4:22 | source() | spread.js:10:8:10:28 | [ 1, 2, ... nt, 3 ] | +| spread.js:4:15:4:22 | source() | spread.js:18:8:18:8 | y | +| spread.js:4:15:4:22 | source() | spread.js:24:8:24:8 | y | | static-capture-groups.js:2:17:2:24 | source() | static-capture-groups.js:5:14:5:22 | RegExp.$1 | | static-capture-groups.js:2:17:2:24 | source() | static-capture-groups.js:15:14:15:22 | RegExp.$1 | | static-capture-groups.js:2:17:2:24 | source() | static-capture-groups.js:17:14:17:22 | RegExp.$1 | diff --git a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected index a90bae109998..b4b3458cb8ee 100644 --- a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected @@ -22,6 +22,8 @@ legacyDataFlowDifference | nested-props.js:27:18:27:25 | source() | nested-props.js:28:10:28:14 | obj.x | only flow with NEW data flow library | | nested-props.js:51:22:51:29 | source() | nested-props.js:52:10:52:16 | obj.x.y | only flow with NEW data flow library | | sanitizer-guards.js:57:11:57:18 | source() | sanitizer-guards.js:64:8:64:8 | x | only flow with NEW data flow library | +| spread.js:4:15:4:22 | source() | spread.js:18:8:18:8 | y | only flow with NEW data flow library | +| spread.js:4:15:4:22 | source() | spread.js:24:8:24:8 | y | only flow with NEW data flow library | | tst.js:2:13:2:20 | source() | tst.js:35:14:35:16 | ary | only flow with NEW data flow library | | tst.js:2:13:2:20 | source() | tst.js:41:14:41:16 | ary | only flow with NEW data flow library | | use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:15:10:15:10 | x | only flow with NEW data flow library | @@ -176,6 +178,8 @@ flow | sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:98:7:98:7 | x | | sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:102:10:102:10 | x | | sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:104:7:104:7 | x | +| spread.js:4:15:4:22 | source() | spread.js:18:8:18:8 | y | +| spread.js:4:15:4:22 | source() | spread.js:24:8:24:8 | y | | thisAssignments.js:4:17:4:24 | source() | thisAssignments.js:5:10:5:18 | obj.field | | thisAssignments.js:7:19:7:26 | source() | thisAssignments.js:8:10:8:20 | this.field2 | | tst.js:2:13:2:20 | source() | tst.js:4:10:4:10 | x | diff --git a/javascript/ql/test/library-tests/TaintTracking/spread.js b/javascript/ql/test/library-tests/TaintTracking/spread.js index 1a2939b6f1d6..34bbb9432533 100644 --- a/javascript/ql/test/library-tests/TaintTracking/spread.js +++ b/javascript/ql/test/library-tests/TaintTracking/spread.js @@ -1,9 +1,26 @@ +import 'dummy'; + function test() { let taint = source(); - + sink({ ...taint }); // NOT OK sink({ f: 'hello', ...taint, g: 'world' }); // NOT OK sink([ ...taint ]); // NOT OK sink([ 1, 2, ...taint, 3 ]); // NOT OK + + fn1(...['x', taint, 'z']); + fn2.apply(undefined, ['x', taint, 'z']); +} + +function fn1(x, y, z) { + sink(x); + sink(y); // NOT OK + sink(z); +} + +function fn2(x, y, z) { + sink(x); + sink(y); // NOT OK + sink(z); } From 3e196f83f1c1e4acb7ca0cd494fe46dd7f474a35 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 23 Aug 2024 13:43:25 +0200 Subject: [PATCH 25/37] JS: Update Promises/flow2 test --- javascript/ql/test/library-tests/Promises/flow2.js | 2 +- javascript/ql/test/library-tests/Promises/tests.expected | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/javascript/ql/test/library-tests/Promises/flow2.js b/javascript/ql/test/library-tests/Promises/flow2.js index 87994bd8245b..0a29ed35f8e3 100644 --- a/javascript/ql/test/library-tests/Promises/flow2.js +++ b/javascript/ql/test/library-tests/Promises/flow2.js @@ -2,7 +2,7 @@ var source = "source"; Promise.all([source, "clean"]).then((arr) => { - sink(arr); // OK + sink(arr); // NOT OK - implicit read of array element sink(arr[0]); // NOT OK sink(arr[1]); // OK }) diff --git a/javascript/ql/test/library-tests/Promises/tests.expected b/javascript/ql/test/library-tests/Promises/tests.expected index 1b0d54662816..52c00a11d50c 100644 --- a/javascript/ql/test/library-tests/Promises/tests.expected +++ b/javascript/ql/test/library-tests/Promises/tests.expected @@ -274,6 +274,7 @@ flow | flow.js:136:15:136:22 | "source" | flow.js:142:7:142:19 | await async() | | flow.js:136:15:136:22 | "source" | flow.js:155:9:155:9 | e | exclusiveTaintFlow +| flow2.js:2:15:2:22 | "source" | flow2.js:5:8:5:10 | arr | | flow.js:136:15:136:22 | "source" | flow.js:141:7:141:13 | async() | | flow.js:160:15:160:22 | "source" | flow.js:164:39:164:39 | x | | flow.js:160:15:160:22 | "source" | flow.js:167:7:167:9 | foo | @@ -466,3 +467,4 @@ typetrack valueFlowDifference | flow2.js:2:15:2:22 | "source" | flow2.js:20:7:20:14 | tainted3 | only flow with NEW data flow library | taintFlowDifference +| flow2.js:2:15:2:22 | "source" | flow2.js:5:8:5:10 | arr | only flow with NEW data flow library | From 2e2181be2c7b6334509990158216873ef4f16cde Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 27 Aug 2024 11:30:53 +0200 Subject: [PATCH 26/37] JS: Update test output that only affects nodes/edges/subpaths --- .../UntrustedDataToExternalAPI.expected | 1 - .../CommandInjection.expected | 37 ++++++++------- .../IndirectCommandInjection.expected | 20 ++++++++ .../UnsafeShellCommandConstruction.expected | 29 ++++++++++-- .../Security/CWE-079/DomBasedXss/Xss.expected | 24 +++++++++- .../XssWithAdditionalSources.expected | 24 +++++++++- .../ExceptionXss/ExceptionXss.expected | 12 ++--- .../CWE-079/StoredXss/StoredXss.expected | 15 ++++++ .../CWE-089/untyped/SqlInjection.expected | 19 ++++++-- .../ImproperCodeSanitization.expected | 7 +++ .../CWE-312/CleartextLogging.expected | 21 +++++++++ .../CWE-400/ReDoS/PolynomialReDoS.expected | 8 ++-- .../ServerSideUrlRedirect.expected | 13 +++++ .../Security/CWE-730/RegExpInjection.expected | 5 ++ .../PrototypePollutingFunction.expected | 47 +++++++++++++++++++ 15 files changed, 244 insertions(+), 38 deletions(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-020/UntrustedDataToExternalAPI/UntrustedDataToExternalAPI.expected b/javascript/ql/test/query-tests/Security/CWE-020/UntrustedDataToExternalAPI/UntrustedDataToExternalAPI.expected index d7e0636b5548..35daa0245350 100644 --- a/javascript/ql/test/query-tests/Security/CWE-020/UntrustedDataToExternalAPI/UntrustedDataToExternalAPI.expected +++ b/javascript/ql/test/query-tests/Security/CWE-020/UntrustedDataToExternalAPI/UntrustedDataToExternalAPI.expected @@ -14,7 +14,6 @@ edges | tst-UntrustedDataToExternalAPI.js:3:5:3:27 | untrusted | tst-UntrustedDataToExternalAPI.js:44:8:44:16 | untrusted | provenance | | | tst-UntrustedDataToExternalAPI.js:3:17:3:27 | window.name | tst-UntrustedDataToExternalAPI.js:3:5:3:27 | untrusted | provenance | | | tst-UntrustedDataToExternalAPI.js:10:13:10:33 | ['x', u ... d, 'y'] [1] | tst-UntrustedDataToExternalAPI.js:10:13:10:33 | ['x', u ... d, 'y'] | provenance | | -| tst-UntrustedDataToExternalAPI.js:10:19:10:27 | untrusted | tst-UntrustedDataToExternalAPI.js:10:13:10:33 | ['x', u ... d, 'y'] | provenance | | | tst-UntrustedDataToExternalAPI.js:10:19:10:27 | untrusted | tst-UntrustedDataToExternalAPI.js:10:13:10:33 | ['x', u ... d, 'y'] [1] | provenance | | | tst-UntrustedDataToExternalAPI.js:13:8:17:5 | {\\n ... }\\n } [y, z] | tst-UntrustedDataToExternalAPI.js:13:8:17:5 | {\\n ... }\\n } | provenance | | | tst-UntrustedDataToExternalAPI.js:14:12:16:9 | {\\n ... } [z] | tst-UntrustedDataToExternalAPI.js:13:8:17:5 | {\\n ... }\\n } [y, z] | provenance | | 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 82521f20efac..f4a573e957cf 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 @@ -16,6 +16,7 @@ edges | child_process-test.js:6:9:6:49 | cmd | child_process-test.js:39:26:39:28 | cmd | provenance | | | child_process-test.js:6:9:6:49 | cmd | child_process-test.js:43:15:43:17 | cmd | provenance | | | child_process-test.js:6:9:6:49 | cmd | child_process-test.js:48:15:48:17 | cmd | provenance | | +| child_process-test.js:6:9:6:49 | cmd | child_process-test.js:48:15:48:17 | cmd | provenance | | | child_process-test.js:6:9:6:49 | cmd | child_process-test.js:53:15:53:17 | cmd | provenance | | | child_process-test.js:6:9:6:49 | cmd | child_process-test.js:56:54:56:56 | cmd | provenance | | | child_process-test.js:6:9:6:49 | cmd | child_process-test.js:56:54:56:56 | cmd | provenance | | @@ -26,12 +27,18 @@ edges | child_process-test.js:6:15:6:49 | url.par ... ry.path | child_process-test.js:6:9:6:49 | cmd | provenance | | | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:6:15:6:38 | url.par ... , true) | provenance | | | child_process-test.js:25:21:25:23 | cmd | child_process-test.js:25:13:25:31 | "foo" + cmd + "bar" | provenance | | -| child_process-test.js:56:46:56:57 | ["bar", cmd] | child_process-test.js:56:25:56:58 | ['/C', ... , cmd]) | provenance | | +| child_process-test.js:46:9:46:17 | args [1] | child_process-test.js:49:15:49:18 | args [1] | provenance | | +| child_process-test.js:48:5:48:8 | [post update] args [1] | child_process-test.js:46:9:46:17 | args [1] | provenance | | +| child_process-test.js:48:15:48:17 | cmd | child_process-test.js:48:5:48:8 | [post update] args [1] | provenance | | +| child_process-test.js:49:15:49:18 | args [1] | child_process-test.js:66:19:66:22 | args [1] | provenance | | +| child_process-test.js:56:25:56:58 | ['/C', ... , cmd]) [ArrayElement] | child_process-test.js:56:25:56:58 | ['/C', ... , cmd]) | provenance | | | child_process-test.js:56:46:56:57 | ["bar", cmd] [1] | child_process-test.js:56:25:56:58 | ['/C', ... , cmd]) | provenance | | -| child_process-test.js:56:54:56:56 | cmd | child_process-test.js:56:25:56:58 | ['/C', ... , cmd]) | provenance | | -| child_process-test.js:56:54:56:56 | cmd | child_process-test.js:56:46:56:57 | ["bar", cmd] | provenance | | +| child_process-test.js:56:46:56:57 | ["bar", cmd] [1] | child_process-test.js:56:25:56:58 | ['/C', ... , cmd]) [ArrayElement] | provenance | | | child_process-test.js:56:54:56:56 | cmd | child_process-test.js:56:46:56:57 | ["bar", cmd] [1] | provenance | | +| child_process-test.js:57:25:57:49 | ['/C', ... at(cmd) [ArrayElement] | child_process-test.js:57:25:57:49 | ['/C', ... at(cmd) | provenance | | | child_process-test.js:57:46:57:48 | cmd | child_process-test.js:57:25:57:49 | ['/C', ... at(cmd) | provenance | | +| child_process-test.js:57:46:57:48 | cmd | child_process-test.js:57:25:57:49 | ['/C', ... at(cmd) [ArrayElement] | provenance | | +| child_process-test.js:66:19:66:22 | args [1] | child_process-test.js:66:19:66:22 | args | provenance | | | child_process-test.js:73:9:73:49 | cmd | child_process-test.js:75:29:75:31 | cmd | provenance | | | child_process-test.js:73:15:73:38 | url.par ... , true) | child_process-test.js:73:9:73:49 | cmd | provenance | | | child_process-test.js:73:25:73:31 | req.url | child_process-test.js:73:15:73:38 | url.par ... , true) | provenance | | @@ -46,26 +53,18 @@ edges | exec-sh.js:19:15:19:38 | url.par ... , true) | exec-sh.js:19:9:19:49 | cmd | provenance | | | exec-sh.js:19:25:19:31 | req.url | exec-sh.js:19:15:19:38 | url.par ... , true) | provenance | | | exec-sh.js:20:12:20:14 | cmd | exec-sh.js:13:17:13:23 | command | provenance | | -| execSeries.js:3:20:3:22 | arr | execSeries.js:5:3:10:4 | (functi ... );\\n }) [arr] | provenance | | -| execSeries.js:3:20:3:22 | arr | execSeries.js:6:14:6:16 | arr | provenance | | | execSeries.js:3:20:3:22 | arr [0] | execSeries.js:5:3:10:4 | (functi ... );\\n }) [arr, 0] | provenance | | | execSeries.js:3:20:3:22 | arr [0] | execSeries.js:6:14:6:16 | arr [0] | provenance | | | execSeries.js:5:3:10:4 | (functi ... );\\n }) [arr, 0] | execSeries.js:6:14:6:16 | arr [0] | provenance | | -| execSeries.js:5:3:10:4 | (functi ... );\\n }) [arr] | execSeries.js:6:14:6:16 | arr | provenance | | -| execSeries.js:6:14:6:16 | arr | execSeries.js:6:14:6:21 | arr[i++] | provenance | | | execSeries.js:6:14:6:16 | arr [0] | execSeries.js:6:14:6:21 | arr[i++] | provenance | | | execSeries.js:6:14:6:21 | arr[i++] | execSeries.js:14:24:14:30 | command | provenance | | -| execSeries.js:13:19:13:26 | commands | execSeries.js:14:13:14:20 | commands | provenance | | | execSeries.js:13:19:13:26 | commands [0] | execSeries.js:14:13:14:20 | commands [0] | provenance | | -| execSeries.js:14:13:14:20 | commands | execSeries.js:3:20:3:22 | arr | provenance | | | execSeries.js:14:13:14:20 | commands [0] | execSeries.js:3:20:3:22 | arr [0] | provenance | | | execSeries.js:14:24:14:30 | command | execSeries.js:14:41:14:47 | command | provenance | | | execSeries.js:18:7:18:58 | cmd | execSeries.js:19:13:19:15 | cmd | provenance | | | execSeries.js:18:13:18:47 | require ... , true) | execSeries.js:18:7:18:58 | cmd | provenance | | | execSeries.js:18:34:18:40 | req.url | execSeries.js:18:13:18:47 | require ... , true) | provenance | | -| execSeries.js:19:12:19:16 | [cmd] | execSeries.js:13:19:13:26 | commands | provenance | | | execSeries.js:19:12:19:16 | [cmd] [0] | execSeries.js:13:19:13:26 | commands [0] | provenance | | -| execSeries.js:19:13:19:15 | cmd | execSeries.js:19:12:19:16 | [cmd] | provenance | | | execSeries.js:19:13:19:15 | cmd | execSeries.js:19:12:19:16 | [cmd] [0] | provenance | | | form-parsers.js:9:19:9:26 | req.file | form-parsers.js:9:8:9:39 | "touch ... nalname | provenance | | | form-parsers.js:13:3:13:11 | req.files | form-parsers.js:13:21:13:24 | file | provenance | | @@ -127,15 +126,22 @@ nodes | child_process-test.js:25:21:25:23 | cmd | semmle.label | cmd | | child_process-test.js:39:26:39:28 | cmd | semmle.label | cmd | | child_process-test.js:43:15:43:17 | cmd | semmle.label | cmd | +| child_process-test.js:46:9:46:17 | args [1] | semmle.label | args [1] | +| child_process-test.js:48:5:48:8 | [post update] args [1] | semmle.label | [post update] args [1] | +| child_process-test.js:48:15:48:17 | cmd | semmle.label | cmd | | child_process-test.js:48:15:48:17 | cmd | semmle.label | cmd | +| child_process-test.js:49:15:49:18 | args [1] | semmle.label | args [1] | | child_process-test.js:53:15:53:17 | cmd | semmle.label | cmd | | child_process-test.js:56:25:56:58 | ['/C', ... , cmd]) | semmle.label | ['/C', ... , cmd]) | -| child_process-test.js:56:46:56:57 | ["bar", cmd] | semmle.label | ["bar", cmd] | +| child_process-test.js:56:25:56:58 | ['/C', ... , cmd]) [ArrayElement] | semmle.label | ['/C', ... , cmd]) [ArrayElement] | | child_process-test.js:56:46:56:57 | ["bar", cmd] [1] | semmle.label | ["bar", cmd] [1] | | child_process-test.js:56:54:56:56 | cmd | semmle.label | cmd | | child_process-test.js:56:54:56:56 | cmd | semmle.label | cmd | | child_process-test.js:57:25:57:49 | ['/C', ... at(cmd) | semmle.label | ['/C', ... at(cmd) | +| child_process-test.js:57:25:57:49 | ['/C', ... at(cmd) [ArrayElement] | semmle.label | ['/C', ... at(cmd) [ArrayElement] | | child_process-test.js:57:46:57:48 | cmd | semmle.label | cmd | +| child_process-test.js:66:19:66:22 | args | semmle.label | args | +| child_process-test.js:66:19:66:22 | args [1] | semmle.label | args [1] | | child_process-test.js:73:9:73:49 | cmd | semmle.label | cmd | | child_process-test.js:73:15:73:38 | url.par ... , true) | semmle.label | url.par ... , true) | | child_process-test.js:73:25:73:31 | req.url | semmle.label | req.url | @@ -155,23 +161,17 @@ nodes | exec-sh.js:19:15:19:38 | url.par ... , true) | semmle.label | url.par ... , true) | | exec-sh.js:19:25:19:31 | req.url | semmle.label | req.url | | exec-sh.js:20:12:20:14 | cmd | semmle.label | cmd | -| execSeries.js:3:20:3:22 | arr | semmle.label | arr | | execSeries.js:3:20:3:22 | arr [0] | semmle.label | arr [0] | | execSeries.js:5:3:10:4 | (functi ... );\\n }) [arr, 0] | semmle.label | (functi ... );\\n }) [arr, 0] | -| execSeries.js:5:3:10:4 | (functi ... );\\n }) [arr] | semmle.label | (functi ... );\\n }) [arr] | -| execSeries.js:6:14:6:16 | arr | semmle.label | arr | | execSeries.js:6:14:6:16 | arr [0] | semmle.label | arr [0] | | execSeries.js:6:14:6:21 | arr[i++] | semmle.label | arr[i++] | -| execSeries.js:13:19:13:26 | commands | semmle.label | commands | | execSeries.js:13:19:13:26 | commands [0] | semmle.label | commands [0] | -| execSeries.js:14:13:14:20 | commands | semmle.label | commands | | execSeries.js:14:13:14:20 | commands [0] | semmle.label | commands [0] | | execSeries.js:14:24:14:30 | command | semmle.label | command | | execSeries.js:14:41:14:47 | command | semmle.label | command | | execSeries.js:18:7:18:58 | cmd | semmle.label | cmd | | execSeries.js:18:13:18:47 | require ... , true) | semmle.label | require ... , true) | | execSeries.js:18:34:18:40 | req.url | semmle.label | req.url | -| execSeries.js:19:12:19:16 | [cmd] | semmle.label | [cmd] | | execSeries.js:19:12:19:16 | [cmd] [0] | semmle.label | [cmd] [0] | | execSeries.js:19:13:19:15 | cmd | semmle.label | cmd | | form-parsers.js:9:8:9:39 | "touch ... nalname | semmle.label | "touch ... nalname | @@ -239,6 +239,7 @@ subpaths | child_process-test.js:57:5:57:50 | cp.spaw ... t(cmd)) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:57:25:57:49 | ['/C', ... at(cmd) | This command line depends on a $@. | child_process-test.js:6:25:6:31 | req.url | user-provided value | | child_process-test.js:62:5:62:39 | cp.exec ... , args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:53:15:53:17 | cmd | This command line depends on a $@. | child_process-test.js:6:25:6:31 | req.url | user-provided value | | child_process-test.js:67:3:67:21 | cp.spawn(cmd, args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:48:15:48:17 | cmd | This command line depends on a $@. | child_process-test.js:6:25:6:31 | req.url | user-provided value | +| child_process-test.js:67:3:67:21 | cp.spawn(cmd, args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:66:19:66:22 | args | This command line depends on a $@. | child_process-test.js:6:25:6:31 | req.url | user-provided value | | child_process-test.js:75:29:75:31 | cmd | child_process-test.js:73:25:73:31 | req.url | child_process-test.js:75:29:75:31 | cmd | This command line depends on a $@. | child_process-test.js:73:25:73:31 | req.url | user-provided value | | child_process-test.js:83:19:83:36 | req.query.fileName | child_process-test.js:83:19:83:36 | req.query.fileName | child_process-test.js:83:19:83:36 | req.query.fileName | This command line depends on a $@. | child_process-test.js:83:19:83:36 | req.query.fileName | user-provided value | | child_process-test.js:94:11:94:35 | "ping " ... ms.host | child_process-test.js:94:21:94:30 | ctx.params | child_process-test.js:94:11:94:35 | "ping " ... ms.host | This command line depends on a $@. | child_process-test.js:94:21:94:30 | ctx.params | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection/IndirectCommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection/IndirectCommandInjection.expected index 26416731806e..a6b90c01ff1f 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection/IndirectCommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection/IndirectCommandInjection.expected @@ -28,10 +28,14 @@ edges | command-line-parameter-command-injection.js:20:26:20:29 | arg0 | command-line-parameter-command-injection.js:20:14:20:29 | "cmd.sh " + arg0 | provenance | | | command-line-parameter-command-injection.js:24:8:24:35 | args | command-line-parameter-command-injection.js:26:32:26:35 | args | provenance | | | command-line-parameter-command-injection.js:24:8:24:35 | args | command-line-parameter-command-injection.js:27:32:27:35 | args | provenance | | +| command-line-parameter-command-injection.js:24:8:24:35 | args [ArrayElement] | command-line-parameter-command-injection.js:27:32:27:35 | args [ArrayElement] | provenance | | | command-line-parameter-command-injection.js:24:15:24:26 | process.argv | command-line-parameter-command-injection.js:24:15:24:35 | process ... lice(2) | provenance | | +| command-line-parameter-command-injection.js:24:15:24:26 | process.argv | command-line-parameter-command-injection.js:24:15:24:35 | process ... lice(2) [ArrayElement] | provenance | | | command-line-parameter-command-injection.js:24:15:24:35 | process ... lice(2) | command-line-parameter-command-injection.js:24:8:24:35 | args | provenance | | +| command-line-parameter-command-injection.js:24:15:24:35 | process ... lice(2) [ArrayElement] | command-line-parameter-command-injection.js:24:8:24:35 | args [ArrayElement] | provenance | | | command-line-parameter-command-injection.js:26:32:26:35 | args | command-line-parameter-command-injection.js:26:14:26:50 | `node $ ... ption"` | provenance | | | command-line-parameter-command-injection.js:27:32:27:35 | args | command-line-parameter-command-injection.js:27:32:27:45 | args.join(' ') | provenance | | +| command-line-parameter-command-injection.js:27:32:27:35 | args [ArrayElement] | command-line-parameter-command-injection.js:27:32:27:45 | args.join(' ') | provenance | | | command-line-parameter-command-injection.js:27:32:27:45 | args.join(' ') | command-line-parameter-command-injection.js:27:14:27:57 | `node $ ... ption"` | provenance | | | command-line-parameter-command-injection.js:30:21:30:46 | require ... rgs")() | command-line-parameter-command-injection.js:30:9:30:50 | "cmd.sh ... )().foo | provenance | | | command-line-parameter-command-injection.js:32:21:32:41 | require ... ").argv | command-line-parameter-command-injection.js:32:9:32:45 | "cmd.sh ... rgv.foo | provenance | | @@ -71,16 +75,24 @@ edges | command-line-parameter-command-injection.js:71:20:71:40 | require ... ').argv | command-line-parameter-command-injection.js:71:6:71:16 | [...taint4] | provenance | | | command-line-parameter-command-injection.js:72:22:72:27 | taint4 | command-line-parameter-command-injection.js:72:10:72:27 | "cmd.sh " + taint4 | provenance | | | command-line-parameter-command-injection.js:76:8:76:35 | argv | command-line-parameter-command-injection.js:79:31:79:34 | argv | provenance | | +| command-line-parameter-command-injection.js:76:8:76:35 | argv [ArrayElement] | command-line-parameter-command-injection.js:79:31:79:34 | argv [ArrayElement] | provenance | | | command-line-parameter-command-injection.js:76:15:76:26 | process.argv | command-line-parameter-command-injection.js:76:15:76:35 | process ... lice(2) | provenance | | +| command-line-parameter-command-injection.js:76:15:76:26 | process.argv | command-line-parameter-command-injection.js:76:15:76:35 | process ... lice(2) [ArrayElement] | provenance | | | command-line-parameter-command-injection.js:76:15:76:35 | process ... lice(2) | command-line-parameter-command-injection.js:76:8:76:35 | argv | provenance | | +| command-line-parameter-command-injection.js:76:15:76:35 | process ... lice(2) [ArrayElement] | command-line-parameter-command-injection.js:76:8:76:35 | argv [ArrayElement] | provenance | | | command-line-parameter-command-injection.js:79:22:79:35 | minimist(argv) | command-line-parameter-command-injection.js:79:10:79:39 | "cmd.sh ... gv).foo | provenance | | | command-line-parameter-command-injection.js:79:31:79:34 | argv | command-line-parameter-command-injection.js:79:22:79:35 | minimist(argv) | provenance | Config | +| command-line-parameter-command-injection.js:79:31:79:34 | argv [ArrayElement] | command-line-parameter-command-injection.js:79:22:79:35 | minimist(argv) | provenance | Config | | command-line-parameter-command-injection.js:82:22:82:50 | subarg( ... ice(2)) | command-line-parameter-command-injection.js:82:10:82:54 | "cmd.sh ... 2)).foo | provenance | | | command-line-parameter-command-injection.js:82:29:82:40 | process.argv | command-line-parameter-command-injection.js:82:29:82:49 | process ... lice(2) | provenance | | +| command-line-parameter-command-injection.js:82:29:82:40 | process.argv | command-line-parameter-command-injection.js:82:29:82:49 | process ... lice(2) [ArrayElement] | provenance | | | command-line-parameter-command-injection.js:82:29:82:49 | process ... lice(2) | command-line-parameter-command-injection.js:82:22:82:50 | subarg( ... ice(2)) | provenance | Config | +| command-line-parameter-command-injection.js:82:29:82:49 | process ... lice(2) [ArrayElement] | command-line-parameter-command-injection.js:82:22:82:50 | subarg( ... ice(2)) | provenance | Config | | command-line-parameter-command-injection.js:85:22:85:55 | yargsPa ... ice(2)) | command-line-parameter-command-injection.js:85:10:85:59 | "cmd.sh ... 2)).foo | provenance | | | command-line-parameter-command-injection.js:85:34:85:45 | process.argv | command-line-parameter-command-injection.js:85:34:85:54 | process ... lice(2) | provenance | | +| command-line-parameter-command-injection.js:85:34:85:45 | process.argv | command-line-parameter-command-injection.js:85:34:85:54 | process ... lice(2) [ArrayElement] | provenance | | | command-line-parameter-command-injection.js:85:34:85:54 | process ... lice(2) | command-line-parameter-command-injection.js:85:22:85:55 | yargsPa ... ice(2)) | provenance | Config | +| command-line-parameter-command-injection.js:85:34:85:54 | process ... lice(2) [ArrayElement] | command-line-parameter-command-injection.js:85:22:85:55 | yargsPa ... ice(2)) | provenance | Config | | command-line-parameter-command-injection.js:88:6:88:37 | flags | command-line-parameter-command-injection.js:89:22:89:26 | flags | provenance | | | command-line-parameter-command-injection.js:88:14:88:37 | args.pa ... s.argv) | command-line-parameter-command-injection.js:88:6:88:37 | flags | provenance | | | command-line-parameter-command-injection.js:88:25:88:36 | process.argv | command-line-parameter-command-injection.js:88:14:88:37 | args.pa ... s.argv) | provenance | Config | @@ -144,12 +156,15 @@ nodes | command-line-parameter-command-injection.js:20:14:20:29 | "cmd.sh " + arg0 | semmle.label | "cmd.sh " + arg0 | | command-line-parameter-command-injection.js:20:26:20:29 | arg0 | semmle.label | arg0 | | command-line-parameter-command-injection.js:24:8:24:35 | args | semmle.label | args | +| command-line-parameter-command-injection.js:24:8:24:35 | args [ArrayElement] | semmle.label | args [ArrayElement] | | command-line-parameter-command-injection.js:24:15:24:26 | process.argv | semmle.label | process.argv | | command-line-parameter-command-injection.js:24:15:24:35 | process ... lice(2) | semmle.label | process ... lice(2) | +| command-line-parameter-command-injection.js:24:15:24:35 | process ... lice(2) [ArrayElement] | semmle.label | process ... lice(2) [ArrayElement] | | command-line-parameter-command-injection.js:26:14:26:50 | `node $ ... ption"` | semmle.label | `node $ ... ption"` | | command-line-parameter-command-injection.js:26:32:26:35 | args | semmle.label | args | | command-line-parameter-command-injection.js:27:14:27:57 | `node $ ... ption"` | semmle.label | `node $ ... ption"` | | command-line-parameter-command-injection.js:27:32:27:35 | args | semmle.label | args | +| command-line-parameter-command-injection.js:27:32:27:35 | args [ArrayElement] | semmle.label | args [ArrayElement] | | command-line-parameter-command-injection.js:27:32:27:45 | args.join(' ') | semmle.label | args.join(' ') | | command-line-parameter-command-injection.js:30:9:30:50 | "cmd.sh ... )().foo | semmle.label | "cmd.sh ... )().foo | | command-line-parameter-command-injection.js:30:21:30:46 | require ... rgs")() | semmle.label | require ... rgs")() | @@ -199,19 +214,24 @@ nodes | command-line-parameter-command-injection.js:72:10:72:27 | "cmd.sh " + taint4 | semmle.label | "cmd.sh " + taint4 | | command-line-parameter-command-injection.js:72:22:72:27 | taint4 | semmle.label | taint4 | | command-line-parameter-command-injection.js:76:8:76:35 | argv | semmle.label | argv | +| command-line-parameter-command-injection.js:76:8:76:35 | argv [ArrayElement] | semmle.label | argv [ArrayElement] | | command-line-parameter-command-injection.js:76:15:76:26 | process.argv | semmle.label | process.argv | | command-line-parameter-command-injection.js:76:15:76:35 | process ... lice(2) | semmle.label | process ... lice(2) | +| command-line-parameter-command-injection.js:76:15:76:35 | process ... lice(2) [ArrayElement] | semmle.label | process ... lice(2) [ArrayElement] | | command-line-parameter-command-injection.js:79:10:79:39 | "cmd.sh ... gv).foo | semmle.label | "cmd.sh ... gv).foo | | command-line-parameter-command-injection.js:79:22:79:35 | minimist(argv) | semmle.label | minimist(argv) | | command-line-parameter-command-injection.js:79:31:79:34 | argv | semmle.label | argv | +| command-line-parameter-command-injection.js:79:31:79:34 | argv [ArrayElement] | semmle.label | argv [ArrayElement] | | command-line-parameter-command-injection.js:82:10:82:54 | "cmd.sh ... 2)).foo | semmle.label | "cmd.sh ... 2)).foo | | command-line-parameter-command-injection.js:82:22:82:50 | subarg( ... ice(2)) | semmle.label | subarg( ... ice(2)) | | command-line-parameter-command-injection.js:82:29:82:40 | process.argv | semmle.label | process.argv | | command-line-parameter-command-injection.js:82:29:82:49 | process ... lice(2) | semmle.label | process ... lice(2) | +| command-line-parameter-command-injection.js:82:29:82:49 | process ... lice(2) [ArrayElement] | semmle.label | process ... lice(2) [ArrayElement] | | command-line-parameter-command-injection.js:85:10:85:59 | "cmd.sh ... 2)).foo | semmle.label | "cmd.sh ... 2)).foo | | command-line-parameter-command-injection.js:85:22:85:55 | yargsPa ... ice(2)) | semmle.label | yargsPa ... ice(2)) | | command-line-parameter-command-injection.js:85:34:85:45 | process.argv | semmle.label | process.argv | | command-line-parameter-command-injection.js:85:34:85:54 | process ... lice(2) | semmle.label | process ... lice(2) | +| command-line-parameter-command-injection.js:85:34:85:54 | process ... lice(2) [ArrayElement] | semmle.label | process ... lice(2) [ArrayElement] | | command-line-parameter-command-injection.js:88:6:88:37 | flags | semmle.label | flags | | command-line-parameter-command-injection.js:88:14:88:37 | args.pa ... s.argv) | semmle.label | args.pa ... s.argv) | | command-line-parameter-command-injection.js:88:25:88:36 | process.argv | semmle.label | process.argv | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected index cf74ed305476..2f91b5e8c764 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected @@ -90,16 +90,25 @@ edges | lib/lib.js:414:40:414:43 | name | lib/lib.js:426:11:426:14 | name | provenance | | | lib/lib.js:414:40:414:43 | name | lib/lib.js:428:36:428:39 | name | provenance | | | lib/lib.js:425:6:425:13 | arr | lib/lib.js:427:14:427:16 | arr | provenance | | +| lib/lib.js:425:6:425:13 | arr [ArrayElement] | lib/lib.js:427:14:427:16 | arr [ArrayElement] | provenance | | | lib/lib.js:426:2:426:4 | [post update] arr | lib/lib.js:425:6:425:13 | arr | provenance | | +| lib/lib.js:426:2:426:4 | [post update] arr [ArrayElement] | lib/lib.js:425:6:425:13 | arr [ArrayElement] | provenance | | | lib/lib.js:426:11:426:14 | name | lib/lib.js:426:2:426:4 | [post update] arr | provenance | | +| lib/lib.js:426:11:426:14 | name | lib/lib.js:426:2:426:4 | [post update] arr [ArrayElement] | provenance | | +| lib/lib.js:427:14:427:16 | arr [ArrayElement] | lib/lib.js:427:14:427:16 | arr | provenance | | +| lib/lib.js:428:14:428:58 | build(" ... + '-') [ArrayElement] | lib/lib.js:428:14:428:58 | build(" ... + '-') | provenance | | | lib/lib.js:428:28:428:57 | (name ? ... ) + '-' | lib/lib.js:428:14:428:58 | build(" ... + '-') | provenance | | +| lib/lib.js:428:28:428:57 | (name ? ... ) + '-' | lib/lib.js:428:14:428:58 | build(" ... + '-') [ArrayElement] | provenance | | | lib/lib.js:428:28:428:57 | (name ? ... ) + '-' | lib/lib.js:431:23:431:26 | last | provenance | | | lib/lib.js:428:36:428:39 | name | lib/lib.js:428:28:428:57 | (name ? ... ) + '-' | provenance | | | lib/lib.js:431:23:431:26 | last | lib/lib.js:436:19:436:22 | last | provenance | | | lib/lib.js:431:23:431:26 | last | lib/lib.js:436:19:436:22 | last | provenance | | | lib/lib.js:432:6:432:13 | arr | lib/lib.js:437:9:437:11 | arr | provenance | | +| lib/lib.js:432:6:432:13 | arr [ArrayElement] | lib/lib.js:437:9:437:11 | arr [ArrayElement] | provenance | | | lib/lib.js:436:10:436:12 | [post update] arr | lib/lib.js:432:6:432:13 | arr | provenance | | +| lib/lib.js:436:10:436:12 | [post update] arr [ArrayElement] | lib/lib.js:432:6:432:13 | arr [ArrayElement] | provenance | | | lib/lib.js:436:19:436:22 | last | lib/lib.js:436:10:436:12 | [post update] arr | provenance | | +| lib/lib.js:436:19:436:22 | last | lib/lib.js:436:10:436:12 | [post update] arr [ArrayElement] | provenance | | | lib/lib.js:441:39:441:42 | name | lib/lib.js:442:24:442:27 | name | provenance | | | lib/lib.js:446:20:446:23 | name | lib/lib.js:447:25:447:28 | name | provenance | | | lib/lib.js:477:33:477:38 | config | lib/lib.js:478:27:478:32 | config | provenance | | @@ -116,9 +125,10 @@ edges | lib/lib.js:509:39:509:42 | name | lib/lib.js:545:23:545:26 | name | provenance | | | lib/lib.js:550:39:550:42 | name | lib/lib.js:555:33:555:36 | name | provenance | | | lib/lib.js:550:39:550:42 | name | lib/lib.js:555:33:555:36 | name | provenance | | -| lib/lib.js:551:33:551:36 | args | lib/lib.js:552:23:552:26 | args | provenance | | -| lib/lib.js:555:25:555:37 | ["-rf", name] | lib/lib.js:551:33:551:36 | args | provenance | | -| lib/lib.js:555:33:555:36 | name | lib/lib.js:555:25:555:37 | ["-rf", name] | provenance | | +| lib/lib.js:551:33:551:36 | args [1] | lib/lib.js:552:23:552:26 | args [1] | provenance | | +| lib/lib.js:552:23:552:26 | args [1] | lib/lib.js:552:23:552:26 | args | provenance | | +| lib/lib.js:555:25:555:37 | ["-rf", name] [1] | lib/lib.js:551:33:551:36 | args [1] | provenance | | +| lib/lib.js:555:33:555:36 | name | lib/lib.js:555:25:555:37 | ["-rf", name] [1] | provenance | | | lib/lib.js:558:41:558:44 | name | lib/lib.js:560:26:560:29 | name | provenance | | | lib/lib.js:558:41:558:44 | name | lib/lib.js:562:26:562:29 | name | provenance | | | lib/lib.js:558:41:558:44 | name | lib/lib.js:566:26:566:29 | name | provenance | | @@ -267,19 +277,26 @@ nodes | lib/lib.js:420:29:420:32 | name | semmle.label | name | | lib/lib.js:424:24:424:27 | name | semmle.label | name | | lib/lib.js:425:6:425:13 | arr | semmle.label | arr | +| lib/lib.js:425:6:425:13 | arr [ArrayElement] | semmle.label | arr [ArrayElement] | | lib/lib.js:426:2:426:4 | [post update] arr | semmle.label | [post update] arr | +| lib/lib.js:426:2:426:4 | [post update] arr [ArrayElement] | semmle.label | [post update] arr [ArrayElement] | | lib/lib.js:426:11:426:14 | name | semmle.label | name | | lib/lib.js:426:11:426:14 | name | semmle.label | name | | lib/lib.js:427:14:427:16 | arr | semmle.label | arr | +| lib/lib.js:427:14:427:16 | arr [ArrayElement] | semmle.label | arr [ArrayElement] | | lib/lib.js:428:14:428:58 | build(" ... + '-') | semmle.label | build(" ... + '-') | +| lib/lib.js:428:14:428:58 | build(" ... + '-') [ArrayElement] | semmle.label | build(" ... + '-') [ArrayElement] | | lib/lib.js:428:28:428:57 | (name ? ... ) + '-' | semmle.label | (name ? ... ) + '-' | | lib/lib.js:428:36:428:39 | name | semmle.label | name | | lib/lib.js:431:23:431:26 | last | semmle.label | last | | lib/lib.js:432:6:432:13 | arr | semmle.label | arr | +| lib/lib.js:432:6:432:13 | arr [ArrayElement] | semmle.label | arr [ArrayElement] | | lib/lib.js:436:10:436:12 | [post update] arr | semmle.label | [post update] arr | +| lib/lib.js:436:10:436:12 | [post update] arr [ArrayElement] | semmle.label | [post update] arr [ArrayElement] | | lib/lib.js:436:19:436:22 | last | semmle.label | last | | lib/lib.js:436:19:436:22 | last | semmle.label | last | | lib/lib.js:437:9:437:11 | arr | semmle.label | arr | +| lib/lib.js:437:9:437:11 | arr [ArrayElement] | semmle.label | arr [ArrayElement] | | lib/lib.js:441:39:441:42 | name | semmle.label | name | | lib/lib.js:442:24:442:27 | name | semmle.label | name | | lib/lib.js:446:20:446:23 | name | semmle.label | name | @@ -301,9 +318,10 @@ nodes | lib/lib.js:543:23:543:26 | name | semmle.label | name | | lib/lib.js:545:23:545:26 | name | semmle.label | name | | lib/lib.js:550:39:550:42 | name | semmle.label | name | -| lib/lib.js:551:33:551:36 | args | semmle.label | args | +| lib/lib.js:551:33:551:36 | args [1] | semmle.label | args [1] | | lib/lib.js:552:23:552:26 | args | semmle.label | args | -| lib/lib.js:555:25:555:37 | ["-rf", name] | semmle.label | ["-rf", name] | +| lib/lib.js:552:23:552:26 | args [1] | semmle.label | args [1] | +| lib/lib.js:555:25:555:37 | ["-rf", name] [1] | semmle.label | ["-rf", name] [1] | | lib/lib.js:555:33:555:36 | name | semmle.label | name | | lib/lib.js:555:33:555:36 | name | semmle.label | name | | lib/lib.js:558:41:558:44 | name | semmle.label | name | @@ -341,6 +359,7 @@ subpaths | lib/lib.js:251:27:251:30 | name | lib/lib.js:239:28:239:28 | s | lib/lib.js:245:9:245:9 | s | lib/lib.js:251:16:251:31 | cleanInput(name) | | lib/lib.js:340:25:340:25 | n | lib/lib.js:329:13:329:13 | x | lib/lib.js:330:9:330:9 | x | lib/lib.js:340:22:340:26 | id(n) | | lib/lib.js:428:28:428:57 | (name ? ... ) + '-' | lib/lib.js:431:23:431:26 | last | lib/lib.js:437:9:437:11 | arr | lib/lib.js:428:14:428:58 | build(" ... + '-') | +| lib/lib.js:428:28:428:57 | (name ? ... ) + '-' | lib/lib.js:431:23:431:26 | last | lib/lib.js:437:9:437:11 | arr [ArrayElement] | lib/lib.js:428:14:428:58 | build(" ... + '-') [ArrayElement] | #select | lib/isImported.js:6:10:6:25 | "rm -rf " + name | lib/isImported.js:5:49:5:52 | name | lib/isImported.js:6:22:6:25 | name | This string concatenation which depends on $@ is later used in a $@. | lib/isImported.js:5:49:5:52 | name | library input | lib/isImported.js:6:2:6:26 | cp.exec ... + name) | shell command | | lib/lib2.js:4:10:4:25 | "rm -rf " + name | lib/lib2.js:3:28:3:31 | name | lib/lib2.js:4:22:4:25 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib2.js:3:28:3:31 | name | library input | lib/lib2.js:4:2:4:26 | cp.exec ... + name) | shell command | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected index db6b84532197..99fd44617758 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected @@ -265,7 +265,9 @@ nodes | react-use-router.js:11:24:11:35 | router.query | semmle.label | router.query | | react-use-router.js:11:24:11:42 | router.query.foobar | semmle.label | router.query.foobar | | react-use-router.js:23:31:23:36 | [post update] router | semmle.label | [post update] router | +| react-use-router.js:23:31:23:36 | [post update] router [ArrayElement] | semmle.label | [post update] router [ArrayElement] | | react-use-router.js:23:43:23:48 | router | semmle.label | router | +| react-use-router.js:23:43:23:48 | router [ArrayElement] | semmle.label | router [ArrayElement] | | react-use-router.js:23:43:23:54 | router.query | semmle.label | router.query | | react-use-router.js:23:43:23:61 | router.query.foobar | semmle.label | router.query.foobar | | react-use-router.js:33:21:33:32 | router.query | semmle.label | router.query | @@ -540,6 +542,7 @@ nodes | tst.js:421:20:421:27 | match[1] | semmle.label | match[1] | | tst.js:424:18:424:37 | window.location.hash | semmle.label | window.location.hash | | tst.js:424:18:424:48 | window. ... it('#') | semmle.label | window. ... it('#') | +| tst.js:424:18:424:48 | window. ... it('#') [ArrayElement] | semmle.label | window. ... it('#') [ArrayElement] | | tst.js:424:18:424:51 | window. ... '#')[1] | semmle.label | window. ... '#')[1] | | tst.js:428:7:428:39 | target | semmle.label | target | | tst.js:428:16:428:39 | documen ... .search | semmle.label | documen ... .search | @@ -590,6 +593,7 @@ nodes | various-concat-obfuscations.js:5:12:5:18 | tainted | semmle.label | tainted | | various-concat-obfuscations.js:6:4:6:26 | "
" ... ainted) | semmle.label | "
" ... ainted) | | various-concat-obfuscations.js:6:4:6:43 | "
" ... /div>") | semmle.label | "
" ... /div>") | +| various-concat-obfuscations.js:6:4:6:43 | "
" ... /div>") [ArrayElement] | semmle.label | "
" ... /div>") [ArrayElement] | | various-concat-obfuscations.js:6:19:6:25 | tainted | semmle.label | tainted | | various-concat-obfuscations.js:7:4:7:31 | ["
... /div>"] | semmle.label | ["
... /div>"] | | various-concat-obfuscations.js:7:4:7:38 | ["
... .join() | semmle.label | ["
... .join() | @@ -600,6 +604,7 @@ nodes | various-concat-obfuscations.js:10:16:10:22 | tainted | semmle.label | tainted | | various-concat-obfuscations.js:11:4:11:31 | "
") | semmle.label | "
") | +| various-concat-obfuscations.js:11:4:11:44 | "
") [ArrayElement] | semmle.label | "
") [ArrayElement] | | various-concat-obfuscations.js:11:24:11:30 | tainted | semmle.label | tainted | | various-concat-obfuscations.js:12:4:12:34 | ["
"] | semmle.label | ["
"] | | various-concat-obfuscations.js:12:4:12:41 | ["
') | semmle.label | '
') | +| various-concat-obfuscations.js:18:10:18:105 | '
') [ArrayElement] | semmle.label | '
') [ArrayElement] | | various-concat-obfuscations.js:18:32:18:36 | attrs | semmle.label | attrs | | various-concat-obfuscations.js:18:32:18:48 | attrs.defaultattr | semmle.label | attrs.defaultattr | | various-concat-obfuscations.js:18:32:18:58 | attrs.d ... 'left' | semmle.label | attrs.d ... 'left' | @@ -621,6 +627,7 @@ nodes | various-concat-obfuscations.js:20:17:20:40 | documen ... .search | semmle.label | documen ... .search | | various-concat-obfuscations.js:20:17:20:46 | documen ... h.attrs | semmle.label | documen ... h.attrs | | various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) | semmle.label | indirec ... .attrs) | +| various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) [ArrayElement] | semmle.label | indirec ... .attrs) [ArrayElement] | | various-concat-obfuscations.js:21:17:21:40 | documen ... .search | semmle.label | documen ... .search | | various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | semmle.label | documen ... h.attrs | | winjs.js:2:7:2:53 | tainted | semmle.label | tainted | @@ -882,9 +889,12 @@ edges | react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | provenance | | | react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar | provenance | | | react-use-router.js:23:31:23:36 | [post update] router | react-use-router.js:23:43:23:48 | router | provenance | | +| react-use-router.js:23:31:23:36 | [post update] router [ArrayElement] | react-use-router.js:23:43:23:48 | router [ArrayElement] | provenance | | | react-use-router.js:23:43:23:48 | router | react-use-router.js:23:43:23:54 | router.query | provenance | | +| react-use-router.js:23:43:23:48 | router [ArrayElement] | react-use-router.js:23:43:23:54 | router.query | provenance | | | react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar | provenance | | | react-use-router.js:23:43:23:61 | router.query.foobar | react-use-router.js:23:31:23:36 | [post update] router | provenance | | +| react-use-router.js:23:43:23:61 | router.query.foobar | react-use-router.js:23:31:23:36 | [post update] router [ArrayElement] | provenance | | | react-use-router.js:33:21:33:32 | router.query | react-use-router.js:33:21:33:39 | router.query.foobar | provenance | | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | provenance | | | react-use-state.js:4:10:4:14 | state | react-use-state.js:4:9:4:49 | state | provenance | | @@ -1026,7 +1036,7 @@ edges | tst.js:70:1:70:27 | [,docum ... search] | tst.js:70:46:70:46 | x | provenance | | | tst.js:70:1:70:27 | [,docum ... search] | tst.js:70:46:70:46 | x | provenance | Config | | tst.js:70:1:70:27 | [,docum ... search] [1] | tst.js:70:46:70:46 | x | provenance | | -| tst.js:70:3:70:26 | documen ... .search | tst.js:70:1:70:27 | [,docum ... search] | provenance | | +| tst.js:70:1:70:27 | [,docum ... search] [1] | tst.js:70:46:70:46 | x | provenance | Config | | tst.js:70:3:70:26 | documen ... .search | tst.js:70:1:70:27 | [,docum ... search] | provenance | Config | | tst.js:70:3:70:26 | documen ... .search | tst.js:70:1:70:27 | [,docum ... search] [1] | provenance | | | tst.js:70:46:70:46 | x | tst.js:73:20:73:20 | x | provenance | | @@ -1134,8 +1144,11 @@ edges | tst.js:421:20:421:24 | match | tst.js:421:20:421:27 | match[1] | provenance | Config | | tst.js:424:18:424:37 | window.location.hash | tst.js:424:18:424:48 | window. ... it('#') | provenance | | | tst.js:424:18:424:37 | window.location.hash | tst.js:424:18:424:48 | window. ... it('#') | provenance | Config | +| tst.js:424:18:424:37 | window.location.hash | tst.js:424:18:424:48 | window. ... it('#') [ArrayElement] | provenance | | | tst.js:424:18:424:48 | window. ... it('#') | tst.js:424:18:424:51 | window. ... '#')[1] | provenance | | | tst.js:424:18:424:48 | window. ... it('#') | tst.js:424:18:424:51 | window. ... '#')[1] | provenance | Config | +| tst.js:424:18:424:48 | window. ... it('#') [ArrayElement] | tst.js:424:18:424:51 | window. ... '#')[1] | provenance | | +| tst.js:424:18:424:48 | window. ... it('#') [ArrayElement] | tst.js:424:18:424:51 | window. ... '#')[1] | provenance | Config | | tst.js:428:7:428:39 | target | tst.js:430:18:430:23 | target | provenance | | | tst.js:428:16:428:39 | documen ... .search | tst.js:428:7:428:39 | target | provenance | | | tst.js:430:18:430:23 | target | tst.js:430:18:430:89 | target. ... data>') | provenance | | @@ -1184,12 +1197,16 @@ edges | various-concat-obfuscations.js:4:14:4:20 | tainted | various-concat-obfuscations.js:4:4:4:31 | "
" ...
" | provenance | Config | | various-concat-obfuscations.js:5:12:5:18 | tainted | various-concat-obfuscations.js:5:4:5:26 | `
$ ...
` | provenance | Config | | various-concat-obfuscations.js:6:4:6:26 | "
" ... ainted) | various-concat-obfuscations.js:6:4:6:43 | "
" ... /div>") | provenance | | +| various-concat-obfuscations.js:6:4:6:26 | "
" ... ainted) | various-concat-obfuscations.js:6:4:6:43 | "
" ... /div>") [ArrayElement] | provenance | | +| various-concat-obfuscations.js:6:4:6:43 | "
" ... /div>") [ArrayElement] | various-concat-obfuscations.js:6:4:6:43 | "
" ... /div>") | provenance | | | various-concat-obfuscations.js:6:19:6:25 | tainted | various-concat-obfuscations.js:6:4:6:26 | "
" ... ainted) | provenance | Config | | various-concat-obfuscations.js:7:4:7:31 | ["
... /div>"] | various-concat-obfuscations.js:7:4:7:38 | ["
... .join() | provenance | | | various-concat-obfuscations.js:7:14:7:20 | tainted | various-concat-obfuscations.js:7:4:7:31 | ["
... /div>"] | provenance | Config | | various-concat-obfuscations.js:9:19:9:25 | tainted | various-concat-obfuscations.js:9:4:9:34 | "
" | provenance | Config | | various-concat-obfuscations.js:10:16:10:22 | tainted | various-concat-obfuscations.js:10:4:10:27 | `
` | provenance | Config | | various-concat-obfuscations.js:11:4:11:31 | "
") | provenance | | +| various-concat-obfuscations.js:11:4:11:31 | "
") [ArrayElement] | provenance | | +| various-concat-obfuscations.js:11:4:11:44 | "
") [ArrayElement] | various-concat-obfuscations.js:11:4:11:44 | "
") | provenance | | | various-concat-obfuscations.js:11:24:11:30 | tainted | various-concat-obfuscations.js:11:4:11:31 | "
"] | various-concat-obfuscations.js:12:4:12:41 | ["
"] | provenance | Config | @@ -1202,7 +1219,9 @@ edges | various-concat-obfuscations.js:18:10:18:59 | '
') | provenance | | +| various-concat-obfuscations.js:18:10:18:88 | '
') [ArrayElement] | provenance | | | various-concat-obfuscations.js:18:10:18:88 | '
') | provenance | | +| various-concat-obfuscations.js:18:10:18:88 | '
') [ArrayElement] | provenance | | | various-concat-obfuscations.js:18:32:18:36 | attrs | various-concat-obfuscations.js:18:32:18:48 | attrs.defaultattr | provenance | | | various-concat-obfuscations.js:18:32:18:36 | attrs | various-concat-obfuscations.js:18:32:18:48 | attrs.defaultattr | provenance | Config | | various-concat-obfuscations.js:18:32:18:48 | attrs.defaultattr | various-concat-obfuscations.js:18:32:18:58 | attrs.d ... 'left' | provenance | | @@ -1211,10 +1230,12 @@ edges | various-concat-obfuscations.js:20:17:20:40 | documen ... .search | various-concat-obfuscations.js:20:17:20:46 | documen ... h.attrs | provenance | Config | | various-concat-obfuscations.js:20:17:20:46 | documen ... h.attrs | various-concat-obfuscations.js:14:24:14:28 | attrs | provenance | | | various-concat-obfuscations.js:20:17:20:46 | documen ... h.attrs | various-concat-obfuscations.js:20:4:20:47 | indirec ... .attrs) | provenance | Config | +| various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) [ArrayElement] | various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) | provenance | | | various-concat-obfuscations.js:21:17:21:40 | documen ... .search | various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | provenance | | | various-concat-obfuscations.js:21:17:21:40 | documen ... .search | various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | provenance | Config | | various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | various-concat-obfuscations.js:17:24:17:28 | attrs | provenance | | | various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) | provenance | Config | +| various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) [ArrayElement] | provenance | Config | | winjs.js:2:7:2:53 | tainted | winjs.js:3:43:3:49 | tainted | provenance | | | winjs.js:2:7:2:53 | tainted | winjs.js:4:43:4:49 | tainted | provenance | | | winjs.js:2:17:2:40 | documen ... .search | winjs.js:2:17:2:53 | documen ... ring(1) | provenance | | @@ -1232,6 +1253,7 @@ subpaths | tst.js:58:26:58:30 | bar() | tst.js:48:15:48:15 | s | tst.js:50:12:50:22 | s.substr(1) | tst.js:58:21:58:31 | chop(bar()) | | various-concat-obfuscations.js:20:17:20:46 | documen ... h.attrs | various-concat-obfuscations.js:14:24:14:28 | attrs | various-concat-obfuscations.js:15:10:15:83 | '
' | various-concat-obfuscations.js:20:4:20:47 | indirec ... .attrs) | | various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | various-concat-obfuscations.js:17:24:17:28 | attrs | various-concat-obfuscations.js:18:10:18:105 | '
') | various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) | +| various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | various-concat-obfuscations.js:17:24:17:28 | attrs | various-concat-obfuscations.js:18:10:18:105 | '
') [ArrayElement] | various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) [ArrayElement] | #select | addEventListener.js:2:20:2:29 | event.data | addEventListener.js:1:43:1:47 | event | addEventListener.js:2:20:2:29 | event.data | Cross-site scripting vulnerability due to $@. | addEventListener.js:1:43:1:47 | event | user-provided value | | addEventListener.js:6:20:6:23 | data | addEventListener.js:5:43:5:48 | {data} | addEventListener.js:6:20:6:23 | data | Cross-site scripting vulnerability due to $@. | addEventListener.js:5:43:5:48 | {data} | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected index 2cbf440a6b5c..afd5effb4c39 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected @@ -270,7 +270,9 @@ nodes | react-use-router.js:11:24:11:35 | router.query | semmle.label | router.query | | react-use-router.js:11:24:11:42 | router.query.foobar | semmle.label | router.query.foobar | | react-use-router.js:23:31:23:36 | [post update] router | semmle.label | [post update] router | +| react-use-router.js:23:31:23:36 | [post update] router [ArrayElement] | semmle.label | [post update] router [ArrayElement] | | react-use-router.js:23:43:23:48 | router | semmle.label | router | +| react-use-router.js:23:43:23:48 | router [ArrayElement] | semmle.label | router [ArrayElement] | | react-use-router.js:23:43:23:54 | router.query | semmle.label | router.query | | react-use-router.js:23:43:23:61 | router.query.foobar | semmle.label | router.query.foobar | | react-use-router.js:33:21:33:32 | router.query | semmle.label | router.query | @@ -545,6 +547,7 @@ nodes | tst.js:421:20:421:27 | match[1] | semmle.label | match[1] | | tst.js:424:18:424:37 | window.location.hash | semmle.label | window.location.hash | | tst.js:424:18:424:48 | window. ... it('#') | semmle.label | window. ... it('#') | +| tst.js:424:18:424:48 | window. ... it('#') [ArrayElement] | semmle.label | window. ... it('#') [ArrayElement] | | tst.js:424:18:424:51 | window. ... '#')[1] | semmle.label | window. ... '#')[1] | | tst.js:428:7:428:39 | target | semmle.label | target | | tst.js:428:16:428:39 | documen ... .search | semmle.label | documen ... .search | @@ -597,6 +600,7 @@ nodes | various-concat-obfuscations.js:5:12:5:18 | tainted | semmle.label | tainted | | various-concat-obfuscations.js:6:4:6:26 | "
" ... ainted) | semmle.label | "
" ... ainted) | | various-concat-obfuscations.js:6:4:6:43 | "
" ... /div>") | semmle.label | "
" ... /div>") | +| various-concat-obfuscations.js:6:4:6:43 | "
" ... /div>") [ArrayElement] | semmle.label | "
" ... /div>") [ArrayElement] | | various-concat-obfuscations.js:6:19:6:25 | tainted | semmle.label | tainted | | various-concat-obfuscations.js:7:4:7:31 | ["
... /div>"] | semmle.label | ["
... /div>"] | | various-concat-obfuscations.js:7:4:7:38 | ["
... .join() | semmle.label | ["
... .join() | @@ -607,6 +611,7 @@ nodes | various-concat-obfuscations.js:10:16:10:22 | tainted | semmle.label | tainted | | various-concat-obfuscations.js:11:4:11:31 | "
") | semmle.label | "
") | +| various-concat-obfuscations.js:11:4:11:44 | "
") [ArrayElement] | semmle.label | "
") [ArrayElement] | | various-concat-obfuscations.js:11:24:11:30 | tainted | semmle.label | tainted | | various-concat-obfuscations.js:12:4:12:34 | ["
"] | semmle.label | ["
"] | | various-concat-obfuscations.js:12:4:12:41 | ["
') | semmle.label | '
') | +| various-concat-obfuscations.js:18:10:18:105 | '
') [ArrayElement] | semmle.label | '
') [ArrayElement] | | various-concat-obfuscations.js:18:32:18:36 | attrs | semmle.label | attrs | | various-concat-obfuscations.js:18:32:18:48 | attrs.defaultattr | semmle.label | attrs.defaultattr | | various-concat-obfuscations.js:18:32:18:58 | attrs.d ... 'left' | semmle.label | attrs.d ... 'left' | @@ -628,6 +634,7 @@ nodes | various-concat-obfuscations.js:20:17:20:40 | documen ... .search | semmle.label | documen ... .search | | various-concat-obfuscations.js:20:17:20:46 | documen ... h.attrs | semmle.label | documen ... h.attrs | | various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) | semmle.label | indirec ... .attrs) | +| various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) [ArrayElement] | semmle.label | indirec ... .attrs) [ArrayElement] | | various-concat-obfuscations.js:21:17:21:40 | documen ... .search | semmle.label | documen ... .search | | various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | semmle.label | documen ... h.attrs | | winjs.js:2:7:2:53 | tainted | semmle.label | tainted | @@ -907,9 +914,12 @@ edges | react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | provenance | | | react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar | provenance | | | react-use-router.js:23:31:23:36 | [post update] router | react-use-router.js:23:43:23:48 | router | provenance | | +| react-use-router.js:23:31:23:36 | [post update] router [ArrayElement] | react-use-router.js:23:43:23:48 | router [ArrayElement] | provenance | | | react-use-router.js:23:43:23:48 | router | react-use-router.js:23:43:23:54 | router.query | provenance | | +| react-use-router.js:23:43:23:48 | router [ArrayElement] | react-use-router.js:23:43:23:54 | router.query | provenance | | | react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar | provenance | | | react-use-router.js:23:43:23:61 | router.query.foobar | react-use-router.js:23:31:23:36 | [post update] router | provenance | | +| react-use-router.js:23:43:23:61 | router.query.foobar | react-use-router.js:23:31:23:36 | [post update] router [ArrayElement] | provenance | | | react-use-router.js:33:21:33:32 | router.query | react-use-router.js:33:21:33:39 | router.query.foobar | provenance | | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | provenance | | | react-use-state.js:4:10:4:14 | state | react-use-state.js:4:9:4:49 | state | provenance | | @@ -1051,7 +1061,7 @@ edges | tst.js:70:1:70:27 | [,docum ... search] | tst.js:70:46:70:46 | x | provenance | | | tst.js:70:1:70:27 | [,docum ... search] | tst.js:70:46:70:46 | x | provenance | Config | | tst.js:70:1:70:27 | [,docum ... search] [1] | tst.js:70:46:70:46 | x | provenance | | -| tst.js:70:3:70:26 | documen ... .search | tst.js:70:1:70:27 | [,docum ... search] | provenance | | +| tst.js:70:1:70:27 | [,docum ... search] [1] | tst.js:70:46:70:46 | x | provenance | Config | | tst.js:70:3:70:26 | documen ... .search | tst.js:70:1:70:27 | [,docum ... search] | provenance | Config | | tst.js:70:3:70:26 | documen ... .search | tst.js:70:1:70:27 | [,docum ... search] [1] | provenance | | | tst.js:70:46:70:46 | x | tst.js:73:20:73:20 | x | provenance | | @@ -1159,8 +1169,11 @@ edges | tst.js:421:20:421:24 | match | tst.js:421:20:421:27 | match[1] | provenance | Config | | tst.js:424:18:424:37 | window.location.hash | tst.js:424:18:424:48 | window. ... it('#') | provenance | | | tst.js:424:18:424:37 | window.location.hash | tst.js:424:18:424:48 | window. ... it('#') | provenance | Config | +| tst.js:424:18:424:37 | window.location.hash | tst.js:424:18:424:48 | window. ... it('#') [ArrayElement] | provenance | | | tst.js:424:18:424:48 | window. ... it('#') | tst.js:424:18:424:51 | window. ... '#')[1] | provenance | | | tst.js:424:18:424:48 | window. ... it('#') | tst.js:424:18:424:51 | window. ... '#')[1] | provenance | Config | +| tst.js:424:18:424:48 | window. ... it('#') [ArrayElement] | tst.js:424:18:424:51 | window. ... '#')[1] | provenance | | +| tst.js:424:18:424:48 | window. ... it('#') [ArrayElement] | tst.js:424:18:424:51 | window. ... '#')[1] | provenance | Config | | tst.js:428:7:428:39 | target | tst.js:430:18:430:23 | target | provenance | | | tst.js:428:16:428:39 | documen ... .search | tst.js:428:7:428:39 | target | provenance | | | tst.js:430:18:430:23 | target | tst.js:430:18:430:89 | target. ... data>') | provenance | | @@ -1210,12 +1223,16 @@ edges | various-concat-obfuscations.js:4:14:4:20 | tainted | various-concat-obfuscations.js:4:4:4:31 | "
" ...
" | provenance | Config | | various-concat-obfuscations.js:5:12:5:18 | tainted | various-concat-obfuscations.js:5:4:5:26 | `
$ ...
` | provenance | Config | | various-concat-obfuscations.js:6:4:6:26 | "
" ... ainted) | various-concat-obfuscations.js:6:4:6:43 | "
" ... /div>") | provenance | | +| various-concat-obfuscations.js:6:4:6:26 | "
" ... ainted) | various-concat-obfuscations.js:6:4:6:43 | "
" ... /div>") [ArrayElement] | provenance | | +| various-concat-obfuscations.js:6:4:6:43 | "
" ... /div>") [ArrayElement] | various-concat-obfuscations.js:6:4:6:43 | "
" ... /div>") | provenance | | | various-concat-obfuscations.js:6:19:6:25 | tainted | various-concat-obfuscations.js:6:4:6:26 | "
" ... ainted) | provenance | Config | | various-concat-obfuscations.js:7:4:7:31 | ["
... /div>"] | various-concat-obfuscations.js:7:4:7:38 | ["
... .join() | provenance | | | various-concat-obfuscations.js:7:14:7:20 | tainted | various-concat-obfuscations.js:7:4:7:31 | ["
... /div>"] | provenance | Config | | various-concat-obfuscations.js:9:19:9:25 | tainted | various-concat-obfuscations.js:9:4:9:34 | "
" | provenance | Config | | various-concat-obfuscations.js:10:16:10:22 | tainted | various-concat-obfuscations.js:10:4:10:27 | `
` | provenance | Config | | various-concat-obfuscations.js:11:4:11:31 | "
") | provenance | | +| various-concat-obfuscations.js:11:4:11:31 | "
") [ArrayElement] | provenance | | +| various-concat-obfuscations.js:11:4:11:44 | "
") [ArrayElement] | various-concat-obfuscations.js:11:4:11:44 | "
") | provenance | | | various-concat-obfuscations.js:11:24:11:30 | tainted | various-concat-obfuscations.js:11:4:11:31 | "
"] | various-concat-obfuscations.js:12:4:12:41 | ["
"] | provenance | Config | @@ -1228,7 +1245,9 @@ edges | various-concat-obfuscations.js:18:10:18:59 | '
') | provenance | | +| various-concat-obfuscations.js:18:10:18:88 | '
') [ArrayElement] | provenance | | | various-concat-obfuscations.js:18:10:18:88 | '
') | provenance | | +| various-concat-obfuscations.js:18:10:18:88 | '
') [ArrayElement] | provenance | | | various-concat-obfuscations.js:18:32:18:36 | attrs | various-concat-obfuscations.js:18:32:18:48 | attrs.defaultattr | provenance | | | various-concat-obfuscations.js:18:32:18:36 | attrs | various-concat-obfuscations.js:18:32:18:48 | attrs.defaultattr | provenance | Config | | various-concat-obfuscations.js:18:32:18:48 | attrs.defaultattr | various-concat-obfuscations.js:18:32:18:58 | attrs.d ... 'left' | provenance | | @@ -1237,10 +1256,12 @@ edges | various-concat-obfuscations.js:20:17:20:40 | documen ... .search | various-concat-obfuscations.js:20:17:20:46 | documen ... h.attrs | provenance | Config | | various-concat-obfuscations.js:20:17:20:46 | documen ... h.attrs | various-concat-obfuscations.js:14:24:14:28 | attrs | provenance | | | various-concat-obfuscations.js:20:17:20:46 | documen ... h.attrs | various-concat-obfuscations.js:20:4:20:47 | indirec ... .attrs) | provenance | Config | +| various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) [ArrayElement] | various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) | provenance | | | various-concat-obfuscations.js:21:17:21:40 | documen ... .search | various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | provenance | | | various-concat-obfuscations.js:21:17:21:40 | documen ... .search | various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | provenance | Config | | various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | various-concat-obfuscations.js:17:24:17:28 | attrs | provenance | | | various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) | provenance | Config | +| various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) [ArrayElement] | provenance | Config | | winjs.js:2:7:2:53 | tainted | winjs.js:3:43:3:49 | tainted | provenance | | | winjs.js:2:7:2:53 | tainted | winjs.js:4:43:4:49 | tainted | provenance | | | winjs.js:2:17:2:40 | documen ... .search | winjs.js:2:17:2:53 | documen ... ring(1) | provenance | | @@ -1270,6 +1291,7 @@ subpaths | tst.js:58:26:58:30 | bar() | tst.js:48:15:48:15 | s | tst.js:50:12:50:22 | s.substr(1) | tst.js:58:21:58:31 | chop(bar()) | | various-concat-obfuscations.js:20:17:20:46 | documen ... h.attrs | various-concat-obfuscations.js:14:24:14:28 | attrs | various-concat-obfuscations.js:15:10:15:83 | '
' | various-concat-obfuscations.js:20:4:20:47 | indirec ... .attrs) | | various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | various-concat-obfuscations.js:17:24:17:28 | attrs | various-concat-obfuscations.js:18:10:18:105 | '
') | various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) | +| various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | various-concat-obfuscations.js:17:24:17:28 | attrs | various-concat-obfuscations.js:18:10:18:105 | '
') [ArrayElement] | various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) [ArrayElement] | #select | jwt.js:6:14:6:20 | decoded | jwt.js:4:36:4:39 | data | jwt.js:6:14:6:20 | decoded | Cross-site scripting vulnerability due to $@. | jwt.js:4:36:4:39 | data | user-provided value | | typeahead.js:10:16:10:18 | loc | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | Cross-site scripting vulnerability due to $@. | typeahead.js:9:28:9:30 | loc | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss/ExceptionXss.expected b/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss/ExceptionXss.expected index 798632aabb1d..a862c47907c3 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss/ExceptionXss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss/ExceptionXss.expected @@ -16,7 +16,7 @@ nodes | exception-xss.js:21:11:21:21 | foo + "bar" | semmle.label | foo + "bar" | | exception-xss.js:22:11:22:11 | e | semmle.label | e | | exception-xss.js:23:18:23:18 | e | semmle.label | e | -| exception-xss.js:33:11:33:22 | ["bar", foo] | semmle.label | ["bar", foo] | +| exception-xss.js:33:11:33:22 | ["bar", foo] [1] | semmle.label | ["bar", foo] [1] | | exception-xss.js:33:19:33:21 | foo | semmle.label | foo | | exception-xss.js:34:11:34:11 | e | semmle.label | e | | exception-xss.js:35:18:35:18 | e | semmle.label | e | @@ -42,7 +42,7 @@ nodes | exception-xss.js:89:11:89:26 | foo.match(/foo/) | semmle.label | foo.match(/foo/) | | exception-xss.js:90:11:90:11 | e | semmle.label | e | | exception-xss.js:91:18:91:18 | e | semmle.label | e | -| exception-xss.js:95:11:95:22 | [foo, "bar"] | semmle.label | [foo, "bar"] | +| exception-xss.js:95:11:95:22 | [foo, "bar"] [0] | semmle.label | [foo, "bar"] [0] | | exception-xss.js:95:12:95:14 | foo | semmle.label | foo | | exception-xss.js:96:11:96:11 | e | semmle.label | e | | exception-xss.js:97:18:97:18 | e | semmle.label | e | @@ -100,8 +100,8 @@ edges | exception-xss.js:21:11:21:13 | foo | exception-xss.js:21:11:21:21 | foo + "bar" | provenance | | | exception-xss.js:21:11:21:21 | foo + "bar" | exception-xss.js:22:11:22:11 | e | provenance | Config | | exception-xss.js:22:11:22:11 | e | exception-xss.js:23:18:23:18 | e | provenance | | -| exception-xss.js:33:11:33:22 | ["bar", foo] | exception-xss.js:34:11:34:11 | e | provenance | Config | -| exception-xss.js:33:19:33:21 | foo | exception-xss.js:33:11:33:22 | ["bar", foo] | provenance | | +| exception-xss.js:33:11:33:22 | ["bar", foo] [1] | exception-xss.js:34:11:34:11 | e | provenance | Config | +| exception-xss.js:33:19:33:21 | foo | exception-xss.js:33:11:33:22 | ["bar", foo] [1] | provenance | | | exception-xss.js:34:11:34:11 | e | exception-xss.js:35:18:35:18 | e | provenance | | | exception-xss.js:38:16:38:16 | x | exception-xss.js:39:9:39:9 | x | provenance | | | exception-xss.js:39:9:39:9 | x | exception-xss.js:39:3:39:10 | exceptional return of deep2(x) | provenance | Config | @@ -124,8 +124,8 @@ edges | exception-xss.js:89:11:89:13 | foo | exception-xss.js:89:11:89:26 | foo.match(/foo/) | provenance | | | exception-xss.js:89:11:89:26 | foo.match(/foo/) | exception-xss.js:90:11:90:11 | e | provenance | Config | | exception-xss.js:90:11:90:11 | e | exception-xss.js:91:18:91:18 | e | provenance | | -| exception-xss.js:95:11:95:22 | [foo, "bar"] | exception-xss.js:96:11:96:11 | e | provenance | Config | -| exception-xss.js:95:12:95:14 | foo | exception-xss.js:95:11:95:22 | [foo, "bar"] | provenance | | +| exception-xss.js:95:11:95:22 | [foo, "bar"] [0] | exception-xss.js:96:11:96:11 | e | provenance | Config | +| exception-xss.js:95:12:95:14 | foo | exception-xss.js:95:11:95:22 | [foo, "bar"] [0] | provenance | | | exception-xss.js:96:11:96:11 | e | exception-xss.js:97:18:97:18 | e | provenance | | | exception-xss.js:102:12:102:14 | foo | exception-xss.js:106:11:106:11 | e | provenance | Config | | exception-xss.js:106:11:106:11 | e | exception-xss.js:107:18:107:18 | e | provenance | | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/StoredXss/StoredXss.expected b/javascript/ql/test/query-tests/Security/CWE-079/StoredXss/StoredXss.expected index 3b3b0501e192..33b967f346c4 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/StoredXss/StoredXss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/StoredXss/StoredXss.expected @@ -10,15 +10,22 @@ edges | xss-through-filenames.js:19:9:19:25 | files2.sort(sort) | xss-through-filenames.js:19:45:19:48 | file | provenance | | | xss-through-filenames.js:19:9:19:25 | files2.sort(sort) | xss-through-filenames.js:22:16:22:21 | files3 | provenance | | | xss-through-filenames.js:19:9:19:25 | files2.sort(sort) | xss-through-filenames.js:22:16:22:21 | files3 | provenance | | +| xss-through-filenames.js:19:9:19:25 | files2.sort(sort) | xss-through-filenames.js:22:16:22:21 | files3 [ArrayElement] | provenance | | +| xss-through-filenames.js:19:9:19:25 | files2.sort(sort) | xss-through-filenames.js:22:16:22:21 | files3 [ArrayElement] | provenance | | | xss-through-filenames.js:19:9:19:25 | files2.sort(sort) [ArrayElement] | xss-through-filenames.js:19:45:19:48 | file | provenance | | | xss-through-filenames.js:19:9:19:25 | files2.sort(sort) [ArrayElement] | xss-through-filenames.js:19:45:19:48 | file | provenance | | | xss-through-filenames.js:19:9:19:25 | files2.sort(sort) [ArrayElement] | xss-through-filenames.js:22:16:22:21 | files3 | provenance | | | xss-through-filenames.js:19:9:19:25 | files2.sort(sort) [ArrayElement] | xss-through-filenames.js:22:16:22:21 | files3 | provenance | | +| xss-through-filenames.js:19:9:19:25 | files2.sort(sort) [ArrayElement] | xss-through-filenames.js:22:16:22:21 | files3 [ArrayElement] | provenance | | +| xss-through-filenames.js:19:9:19:25 | files2.sort(sort) [ArrayElement] | xss-through-filenames.js:22:16:22:21 | files3 [ArrayElement] | provenance | | | xss-through-filenames.js:19:45:19:48 | file | xss-through-filenames.js:20:34:20:37 | file | provenance | | | xss-through-filenames.js:20:25:20:47 | '
  • ' ... '
  • ' | xss-through-filenames.js:20:13:20:18 | [post update] files3 | provenance | | +| xss-through-filenames.js:20:25:20:47 | '
  • ' ... '
  • ' | xss-through-filenames.js:20:13:20:18 | [post update] files3 [ArrayElement] | provenance | | | xss-through-filenames.js:20:34:20:37 | file | xss-through-filenames.js:20:25:20:47 | '
  • ' ... '
  • ' | provenance | | | xss-through-filenames.js:22:16:22:21 | files3 | xss-through-filenames.js:22:16:22:30 | files3.join('') | provenance | | | xss-through-filenames.js:22:16:22:21 | files3 | xss-through-filenames.js:22:16:22:30 | files3.join('') | provenance | | +| xss-through-filenames.js:22:16:22:21 | files3 [ArrayElement] | xss-through-filenames.js:22:16:22:30 | files3.join('') | provenance | | +| xss-through-filenames.js:22:16:22:21 | files3 [ArrayElement] | xss-through-filenames.js:22:16:22:30 | files3.join('') | provenance | | | xss-through-filenames.js:25:43:25:48 | files1 | xss-through-filenames.js:26:19:26:24 | files1 | provenance | | | xss-through-filenames.js:25:43:25:48 | files1 | xss-through-filenames.js:30:9:30:14 | files1 | provenance | | | xss-through-filenames.js:30:9:30:14 | files1 | xss-through-filenames.js:30:34:30:37 | file | provenance | | @@ -29,6 +36,7 @@ edges | xss-through-filenames.js:31:25:31:28 | file | xss-through-filenames.js:31:13:31:18 | [post update] files2 | provenance | | | xss-through-filenames.js:31:25:31:28 | file | xss-through-filenames.js:31:13:31:18 | [post update] files2 [ArrayElement] | provenance | | | xss-through-filenames.js:33:19:33:24 | files2 | xss-through-filenames.js:35:29:35:34 | files2 | provenance | | +| xss-through-filenames.js:33:19:33:24 | files2 [ArrayElement] | xss-through-filenames.js:33:19:33:24 | files2 | provenance | | | xss-through-filenames.js:33:19:33:24 | files2 [ArrayElement] | xss-through-filenames.js:35:29:35:34 | files2 [ArrayElement] | provenance | | | xss-through-filenames.js:35:13:35:35 | files3 | xss-through-filenames.js:37:19:37:24 | files3 | provenance | | | xss-through-filenames.js:35:22:35:35 | format(files2) | xss-through-filenames.js:35:13:35:35 | files3 | provenance | | @@ -51,10 +59,13 @@ nodes | xss-through-filenames.js:19:9:19:25 | files2.sort(sort) [ArrayElement] | semmle.label | files2.sort(sort) [ArrayElement] | | xss-through-filenames.js:19:45:19:48 | file | semmle.label | file | | xss-through-filenames.js:20:13:20:18 | [post update] files3 | semmle.label | [post update] files3 | +| xss-through-filenames.js:20:13:20:18 | [post update] files3 [ArrayElement] | semmle.label | [post update] files3 [ArrayElement] | | xss-through-filenames.js:20:25:20:47 | '
  • ' ... '
  • ' | semmle.label | '
  • ' ... '
  • ' | | xss-through-filenames.js:20:34:20:37 | file | semmle.label | file | | xss-through-filenames.js:22:16:22:21 | files3 | semmle.label | files3 | | xss-through-filenames.js:22:16:22:21 | files3 | semmle.label | files3 | +| xss-through-filenames.js:22:16:22:21 | files3 [ArrayElement] | semmle.label | files3 [ArrayElement] | +| xss-through-filenames.js:22:16:22:21 | files3 [ArrayElement] | semmle.label | files3 [ArrayElement] | | xss-through-filenames.js:22:16:22:30 | files3.join('') | semmle.label | files3.join('') | | xss-through-filenames.js:22:16:22:30 | files3.join('') | semmle.label | files3.join('') | | xss-through-filenames.js:25:43:25:48 | files1 | semmle.label | files1 | @@ -78,8 +89,12 @@ nodes subpaths | xss-through-filenames.js:19:9:19:25 | files2.sort(sort) | xss-through-filenames.js:19:45:19:48 | file | xss-through-filenames.js:20:13:20:18 | [post update] files3 | xss-through-filenames.js:22:16:22:21 | files3 | | xss-through-filenames.js:19:9:19:25 | files2.sort(sort) | xss-through-filenames.js:19:45:19:48 | file | xss-through-filenames.js:20:13:20:18 | [post update] files3 | xss-through-filenames.js:22:16:22:21 | files3 | +| xss-through-filenames.js:19:9:19:25 | files2.sort(sort) | xss-through-filenames.js:19:45:19:48 | file | xss-through-filenames.js:20:13:20:18 | [post update] files3 [ArrayElement] | xss-through-filenames.js:22:16:22:21 | files3 [ArrayElement] | +| xss-through-filenames.js:19:9:19:25 | files2.sort(sort) | xss-through-filenames.js:19:45:19:48 | file | xss-through-filenames.js:20:13:20:18 | [post update] files3 [ArrayElement] | xss-through-filenames.js:22:16:22:21 | files3 [ArrayElement] | | xss-through-filenames.js:19:9:19:25 | files2.sort(sort) [ArrayElement] | xss-through-filenames.js:19:45:19:48 | file | xss-through-filenames.js:20:13:20:18 | [post update] files3 | xss-through-filenames.js:22:16:22:21 | files3 | | xss-through-filenames.js:19:9:19:25 | files2.sort(sort) [ArrayElement] | xss-through-filenames.js:19:45:19:48 | file | xss-through-filenames.js:20:13:20:18 | [post update] files3 | xss-through-filenames.js:22:16:22:21 | files3 | +| xss-through-filenames.js:19:9:19:25 | files2.sort(sort) [ArrayElement] | xss-through-filenames.js:19:45:19:48 | file | xss-through-filenames.js:20:13:20:18 | [post update] files3 [ArrayElement] | xss-through-filenames.js:22:16:22:21 | files3 [ArrayElement] | +| xss-through-filenames.js:19:9:19:25 | files2.sort(sort) [ArrayElement] | xss-through-filenames.js:19:45:19:48 | file | xss-through-filenames.js:20:13:20:18 | [post update] files3 [ArrayElement] | xss-through-filenames.js:22:16:22:21 | files3 [ArrayElement] | | xss-through-filenames.js:30:9:30:14 | files1 | xss-through-filenames.js:30:34:30:37 | file | xss-through-filenames.js:31:13:31:18 | [post update] files2 | xss-through-filenames.js:33:19:33:24 | files2 | | xss-through-filenames.js:30:9:30:14 | files1 | xss-through-filenames.js:30:34:30:37 | file | xss-through-filenames.js:31:13:31:18 | [post update] files2 | xss-through-filenames.js:33:19:33:24 | files2 | | xss-through-filenames.js:30:9:30:14 | files1 | xss-through-filenames.js:30:34:30:37 | file | xss-through-filenames.js:31:13:31:18 | [post update] files2 [ArrayElement] | xss-through-filenames.js:33:19:33:24 | files2 [ArrayElement] | diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected index b70b13b4c1bd..6c1a83cc421d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected @@ -53,11 +53,14 @@ nodes | koarouter.js:5:11:5:33 | version | semmle.label | version | | koarouter.js:5:13:5:19 | version | semmle.label | version | | koarouter.js:11:11:11:28 | conditions | semmle.label | conditions | +| koarouter.js:11:11:11:28 | conditions [ArrayElement] | semmle.label | conditions [ArrayElement] | | koarouter.js:14:9:14:18 | [post update] conditions | semmle.label | [post update] conditions | +| koarouter.js:14:9:14:18 | [post update] conditions [ArrayElement] | semmle.label | [post update] conditions [ArrayElement] | | koarouter.js:14:25:14:46 | `versio ... rsion}` | semmle.label | `versio ... rsion}` | | koarouter.js:14:38:14:44 | version | semmle.label | version | | koarouter.js:17:27:17:77 | `SELECT ... nd ')}` | semmle.label | `SELECT ... nd ')}` | | koarouter.js:17:52:17:61 | conditions | semmle.label | conditions | +| koarouter.js:17:52:17:61 | conditions [ArrayElement] | semmle.label | conditions [ArrayElement] | | koarouter.js:17:52:17:75 | conditi ... and ') | semmle.label | conditi ... and ') | | ldap.js:20:7:20:34 | q | semmle.label | q | | ldap.js:20:11:20:34 | url.par ... , true) | semmle.label | url.par ... , true) | @@ -240,6 +243,9 @@ nodes | pg-promise.js:30:13:30:25 | req.params.id | semmle.label | req.params.id | | pg-promise.js:34:13:34:25 | req.params.id | semmle.label | req.params.id | | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | semmle.label | [\\n ... n\\n ] | +| pg-promise.js:38:13:42:5 | [\\n ... n\\n ] [0] | semmle.label | [\\n ... n\\n ] [0] | +| pg-promise.js:38:13:42:5 | [\\n ... n\\n ] [1] | semmle.label | [\\n ... n\\n ] [1] | +| pg-promise.js:38:13:42:5 | [\\n ... n\\n ] [2] | semmle.label | [\\n ... n\\n ] [2] | | pg-promise.js:39:7:39:19 | req.params.id | semmle.label | req.params.id | | pg-promise.js:40:7:40:21 | req.params.name | semmle.label | req.params.name | | pg-promise.js:41:7:41:20 | req.params.foo | semmle.label | req.params.foo | @@ -325,10 +331,14 @@ edges | koarouter.js:5:11:5:33 | version | koarouter.js:14:38:14:44 | version | provenance | | | koarouter.js:5:13:5:19 | version | koarouter.js:5:11:5:33 | version | provenance | | | koarouter.js:11:11:11:28 | conditions | koarouter.js:17:52:17:61 | conditions | provenance | | +| koarouter.js:11:11:11:28 | conditions [ArrayElement] | koarouter.js:17:52:17:61 | conditions [ArrayElement] | provenance | | | koarouter.js:14:9:14:18 | [post update] conditions | koarouter.js:11:11:11:28 | conditions | provenance | | +| koarouter.js:14:9:14:18 | [post update] conditions [ArrayElement] | koarouter.js:11:11:11:28 | conditions [ArrayElement] | provenance | | | koarouter.js:14:25:14:46 | `versio ... rsion}` | koarouter.js:14:9:14:18 | [post update] conditions | provenance | | +| koarouter.js:14:25:14:46 | `versio ... rsion}` | koarouter.js:14:9:14:18 | [post update] conditions [ArrayElement] | provenance | | | koarouter.js:14:38:14:44 | version | koarouter.js:14:25:14:46 | `versio ... rsion}` | provenance | | | koarouter.js:17:52:17:61 | conditions | koarouter.js:17:52:17:75 | conditi ... and ') | provenance | | +| koarouter.js:17:52:17:61 | conditions [ArrayElement] | koarouter.js:17:52:17:75 | conditi ... and ') | provenance | | | koarouter.js:17:52:17:75 | conditi ... and ') | koarouter.js:17:27:17:77 | `SELECT ... nd ')}` | provenance | | | ldap.js:20:7:20:34 | q | ldap.js:22:18:22:18 | q | provenance | | | ldap.js:20:11:20:34 | url.par ... , true) | ldap.js:20:7:20:34 | q | provenance | | @@ -602,9 +612,12 @@ edges | pg-promise.js:22:11:22:15 | query | pg-promise.js:60:20:60:24 | query | provenance | | | pg-promise.js:22:11:22:15 | query | pg-promise.js:63:23:63:27 | query | provenance | | | pg-promise.js:22:11:22:15 | query | pg-promise.js:64:16:64:20 | query | provenance | | -| pg-promise.js:39:7:39:19 | req.params.id | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | provenance | | -| pg-promise.js:40:7:40:21 | req.params.name | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | provenance | | -| pg-promise.js:41:7:41:20 | req.params.foo | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | provenance | | +| pg-promise.js:38:13:42:5 | [\\n ... n\\n ] [0] | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | provenance | | +| pg-promise.js:38:13:42:5 | [\\n ... n\\n ] [1] | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | provenance | | +| pg-promise.js:38:13:42:5 | [\\n ... n\\n ] [2] | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] | provenance | | +| pg-promise.js:39:7:39:19 | req.params.id | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] [0] | provenance | | +| pg-promise.js:40:7:40:21 | req.params.name | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] [1] | provenance | | +| pg-promise.js:41:7:41:20 | req.params.foo | pg-promise.js:38:13:42:5 | [\\n ... n\\n ] [2] | provenance | | | redis.js:10:16:10:23 | req.body | redis.js:10:16:10:27 | req.body.key | provenance | Config | | redis.js:12:9:12:26 | key | redis.js:13:16:13:18 | key | provenance | | | redis.js:12:9:12:26 | key | redis.js:18:16:18:18 | key | provenance | | diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected index 6e8db0460973..1600e99b12fe 100644 --- a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected @@ -2,20 +2,27 @@ edges | bad-code-sanitization.js:2:12:2:90 | /^[_$a- ... key)}]` | bad-code-sanitization.js:7:31:7:43 | safeProp(key) | provenance | | | bad-code-sanitization.js:2:69:2:87 | JSON.stringify(key) | bad-code-sanitization.js:2:12:2:90 | /^[_$a- ... key)}]` | provenance | | | bad-code-sanitization.js:6:11:6:25 | statements | bad-code-sanitization.js:8:27:8:36 | statements | provenance | | +| bad-code-sanitization.js:6:11:6:25 | statements [ArrayElement] | bad-code-sanitization.js:8:27:8:36 | statements [ArrayElement] | provenance | | | bad-code-sanitization.js:7:5:7:14 | [post update] statements | bad-code-sanitization.js:6:11:6:25 | statements | provenance | | +| bad-code-sanitization.js:7:5:7:14 | [post update] statements [ArrayElement] | bad-code-sanitization.js:6:11:6:25 | statements [ArrayElement] | provenance | | | bad-code-sanitization.js:7:21:7:70 | `${name ... key])}` | bad-code-sanitization.js:7:5:7:14 | [post update] statements | provenance | | +| bad-code-sanitization.js:7:21:7:70 | `${name ... key])}` | bad-code-sanitization.js:7:5:7:14 | [post update] statements [ArrayElement] | provenance | | | bad-code-sanitization.js:7:31:7:43 | safeProp(key) | bad-code-sanitization.js:7:21:7:70 | `${name ... key])}` | provenance | | | bad-code-sanitization.js:8:27:8:36 | statements | bad-code-sanitization.js:8:27:8:46 | statements.join(';') | provenance | | +| bad-code-sanitization.js:8:27:8:36 | statements [ArrayElement] | bad-code-sanitization.js:8:27:8:46 | statements.join(';') | provenance | | | bad-code-sanitization.js:63:11:63:55 | assignment | bad-code-sanitization.js:64:27:64:36 | assignment | provenance | | | bad-code-sanitization.js:63:31:63:49 | JSON.stringify(key) | bad-code-sanitization.js:63:11:63:55 | assignment | provenance | | nodes | bad-code-sanitization.js:2:12:2:90 | /^[_$a- ... key)}]` | semmle.label | /^[_$a- ... key)}]` | | bad-code-sanitization.js:2:69:2:87 | JSON.stringify(key) | semmle.label | JSON.stringify(key) | | bad-code-sanitization.js:6:11:6:25 | statements | semmle.label | statements | +| bad-code-sanitization.js:6:11:6:25 | statements [ArrayElement] | semmle.label | statements [ArrayElement] | | bad-code-sanitization.js:7:5:7:14 | [post update] statements | semmle.label | [post update] statements | +| bad-code-sanitization.js:7:5:7:14 | [post update] statements [ArrayElement] | semmle.label | [post update] statements [ArrayElement] | | bad-code-sanitization.js:7:21:7:70 | `${name ... key])}` | semmle.label | `${name ... key])}` | | bad-code-sanitization.js:7:31:7:43 | safeProp(key) | semmle.label | safeProp(key) | | bad-code-sanitization.js:8:27:8:36 | statements | semmle.label | statements | +| bad-code-sanitization.js:8:27:8:36 | statements [ArrayElement] | semmle.label | statements [ArrayElement] | | bad-code-sanitization.js:8:27:8:46 | statements.join(';') | semmle.label | statements.join(';') | | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | semmle.label | htmlescape(pathname) | | bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | semmle.label | JSON.st ... (input) | diff --git a/javascript/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected b/javascript/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected index 8e50d05362e7..b18ece7460ae 100644 --- a/javascript/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected +++ b/javascript/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected @@ -48,17 +48,32 @@ edges | passwords.js:135:17:135:22 | config [y] | passwords.js:135:17:135:22 | config | provenance | | | passwords.js:136:17:136:22 | config [x] | passwords.js:136:17:136:24 | config.x | provenance | | | passwords.js:137:17:137:22 | config [y] | passwords.js:137:17:137:24 | config.y | provenance | | +| passwords.js:142:26:142:34 | [apply call taint node] | passwords.js:142:26:142:34 | arguments [ArrayElement] | provenance | | +| passwords.js:142:26:142:34 | [apply call taint node] | passwords.js:142:26:142:34 | arguments [ArrayElement] | provenance | | +| passwords.js:142:26:142:34 | arguments | passwords.js:142:26:142:34 | [apply call taint node] | provenance | | +| passwords.js:142:26:142:34 | arguments [0] | passwords.js:142:26:142:34 | [apply call taint node] | provenance | | +| passwords.js:142:26:142:34 | arguments [0] | passwords.js:142:26:142:34 | arguments | provenance | | +| passwords.js:142:26:142:34 | arguments [ArrayElement] | passwords.js:142:26:142:34 | [apply call taint node] | provenance | | +| passwords.js:142:26:142:34 | arguments [ArrayElement] | passwords.js:142:26:142:34 | [apply call taint node] | provenance | | +| passwords.js:142:26:142:34 | arguments [ArrayElement] | passwords.js:142:26:142:34 | arguments | provenance | | +| passwords.js:142:26:142:34 | arguments [ArrayElement] | passwords.js:142:26:142:34 | arguments | provenance | | | passwords.js:146:9:148:5 | config [x] | passwords.js:149:21:149:26 | config [x] | provenance | | | passwords.js:146:18:148:5 | {\\n ... d\\n } [x] | passwords.js:146:9:148:5 | config [x] | provenance | | | passwords.js:147:12:147:19 | password | passwords.js:146:18:148:5 | {\\n ... d\\n } [x] | provenance | | | passwords.js:149:21:149:26 | config [x] | passwords.js:149:21:149:28 | config.x | provenance | | | passwords.js:149:21:149:28 | config.x | passwords.js:142:26:142:34 | arguments | provenance | Config | +| passwords.js:149:21:149:28 | config.x | passwords.js:142:26:142:34 | arguments | provenance | Config | +| passwords.js:149:21:149:28 | config.x | passwords.js:142:26:142:34 | arguments [0] | provenance | | +| passwords.js:150:21:150:31 | process.env | passwords.js:142:26:142:34 | arguments | provenance | Config | | passwords.js:150:21:150:31 | process.env | passwords.js:142:26:142:34 | arguments | provenance | Config | +| passwords.js:150:21:150:31 | process.env | passwords.js:142:26:142:34 | arguments [0] | provenance | | | passwords.js:152:9:152:63 | procdesc | passwords.js:154:21:154:28 | procdesc | provenance | | | passwords.js:152:20:152:44 | Util.in ... ss.env) | passwords.js:152:20:152:63 | Util.in ... /g, '') | provenance | | | passwords.js:152:20:152:63 | Util.in ... /g, '') | passwords.js:152:9:152:63 | procdesc | provenance | | | passwords.js:152:33:152:43 | process.env | passwords.js:152:20:152:44 | Util.in ... ss.env) | provenance | | | passwords.js:154:21:154:28 | procdesc | passwords.js:142:26:142:34 | arguments | provenance | Config | +| passwords.js:154:21:154:28 | procdesc | passwords.js:142:26:142:34 | arguments | provenance | Config | +| passwords.js:154:21:154:28 | procdesc | passwords.js:142:26:142:34 | arguments [0] | provenance | | | passwords.js:163:14:163:21 | password | passwords.js:163:14:163:41 | passwor ... g, "*") | provenance | | | passwords.js:164:14:164:21 | password | passwords.js:164:14:164:42 | passwor ... g, "*") | provenance | | | passwords.js:169:17:169:24 | password | passwords.js:169:17:169:45 | passwor ... g, "*") | provenance | | @@ -137,7 +152,13 @@ nodes | passwords.js:136:17:136:24 | config.x | semmle.label | config.x | | passwords.js:137:17:137:22 | config [y] | semmle.label | config [y] | | passwords.js:137:17:137:24 | config.y | semmle.label | config.y | +| passwords.js:142:26:142:34 | [apply call taint node] | semmle.label | [apply call taint node] | +| passwords.js:142:26:142:34 | [apply call taint node] | semmle.label | [apply call taint node] | +| passwords.js:142:26:142:34 | arguments | semmle.label | arguments | | passwords.js:142:26:142:34 | arguments | semmle.label | arguments | +| passwords.js:142:26:142:34 | arguments [0] | semmle.label | arguments [0] | +| passwords.js:142:26:142:34 | arguments [ArrayElement] | semmle.label | arguments [ArrayElement] | +| passwords.js:142:26:142:34 | arguments [ArrayElement] | semmle.label | arguments [ArrayElement] | | passwords.js:146:9:148:5 | config [x] | semmle.label | config [x] | | passwords.js:146:18:148:5 | {\\n ... d\\n } [x] | semmle.label | {\\n ... d\\n } [x] | | passwords.js:147:12:147:19 | password | semmle.label | password | diff --git a/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/PolynomialReDoS.expected b/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/PolynomialReDoS.expected index 2d21c3324824..da41dd5354d6 100644 --- a/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/PolynomialReDoS.expected +++ b/javascript/ql/test/query-tests/Security/CWE-400/ReDoS/PolynomialReDoS.expected @@ -3,8 +3,9 @@ edges | lib/indirect.js:1:32:1:32 | x | lib/indirect.js:2:16:2:16 | x | provenance | | | lib/lib.js:3:28:3:31 | name | lib/lib.js:4:14:4:17 | name | provenance | | | lib/lib.js:7:19:7:22 | name | lib/lib.js:8:13:8:16 | name | provenance | | -| lib/lib.js:32:32:32:40 | arguments | lib/lib.js:35:1:37:1 | 'arguments' object of function usedWithArguments | provenance | | -| lib/lib.js:35:1:37:1 | 'arguments' object of function usedWithArguments | lib/lib.js:35:28:35:31 | name | provenance | | +| lib/lib.js:32:32:32:40 | [apply call taint node] | lib/lib.js:32:32:32:40 | arguments [ArrayElement] | provenance | | +| lib/lib.js:32:32:32:40 | arguments | lib/lib.js:32:32:32:40 | [apply call taint node] | provenance | | +| lib/lib.js:32:32:32:40 | arguments [ArrayElement] | lib/lib.js:35:28:35:31 | name | provenance | | | lib/lib.js:35:28:35:31 | name | lib/lib.js:36:13:36:16 | name | provenance | | | lib/lib.js:41:32:41:35 | name | lib/lib.js:42:17:42:20 | name | provenance | | | lib/lib.js:41:32:41:35 | name | lib/lib.js:44:12:44:15 | name | provenance | | @@ -359,8 +360,9 @@ nodes | lib/lib.js:4:14:4:17 | name | semmle.label | name | | lib/lib.js:7:19:7:22 | name | semmle.label | name | | lib/lib.js:8:13:8:16 | name | semmle.label | name | +| lib/lib.js:32:32:32:40 | [apply call taint node] | semmle.label | [apply call taint node] | | lib/lib.js:32:32:32:40 | arguments | semmle.label | arguments | -| lib/lib.js:35:1:37:1 | 'arguments' object of function usedWithArguments | semmle.label | 'arguments' object of function usedWithArguments | +| lib/lib.js:32:32:32:40 | arguments [ArrayElement] | semmle.label | arguments [ArrayElement] | | lib/lib.js:35:28:35:31 | name | semmle.label | name | | lib/lib.js:36:13:36:16 | name | semmle.label | name | | lib/lib.js:41:32:41:35 | name | semmle.label | name | diff --git a/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected b/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected index ac29a57bf83d..aa992b9c7070 100644 --- a/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected +++ b/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected @@ -10,6 +10,10 @@ edges | express.js:83:7:83:34 | target | express.js:90:18:90:23 | target | provenance | | | express.js:83:7:83:34 | target | express.js:97:16:97:21 | target | provenance | | | express.js:83:16:83:34 | req.param("target") | express.js:83:7:83:34 | target | provenance | | +| express.js:118:16:118:63 | [req.qu ... ection] | express.js:118:16:118:72 | [req.qu ... oin('') | provenance | | +| express.js:118:16:118:63 | [req.qu ... ection] [0] | express.js:118:16:118:72 | [req.qu ... oin('') | provenance | | +| express.js:118:17:118:30 | req.query.page | express.js:118:16:118:63 | [req.qu ... ection] | provenance | | +| express.js:118:17:118:30 | req.query.page | express.js:118:16:118:63 | [req.qu ... ection] [0] | provenance | | | express.js:118:17:118:30 | req.query.page | express.js:118:16:118:72 | [req.qu ... oin('') | provenance | | | express.js:134:22:134:36 | req.params.user | express.js:134:16:134:36 | '/' + r ... ms.user | provenance | | | express.js:135:23:135:37 | req.params.user | express.js:135:16:135:37 | '//' + ... ms.user | provenance | | @@ -18,9 +22,13 @@ edges | express.js:150:7:150:34 | target | express.js:160:18:160:23 | target | provenance | | | express.js:150:16:150:34 | req.param("target") | express.js:150:7:150:34 | target | provenance | | | express.js:164:7:164:54 | myThing | express.js:165:16:165:22 | myThing | provenance | | +| express.js:164:7:164:54 | myThing [ArrayElement] | express.js:165:16:165:22 | myThing [ArrayElement] | provenance | | | express.js:164:17:164:41 | JSON.st ... .query) | express.js:164:17:164:54 | JSON.st ... (1, -1) | provenance | | +| express.js:164:17:164:41 | JSON.st ... .query) | express.js:164:17:164:54 | JSON.st ... (1, -1) [ArrayElement] | provenance | | | express.js:164:17:164:54 | JSON.st ... (1, -1) | express.js:164:7:164:54 | myThing | provenance | | +| express.js:164:17:164:54 | JSON.st ... (1, -1) [ArrayElement] | express.js:164:7:164:54 | myThing [ArrayElement] | provenance | | | express.js:164:32:164:40 | req.query | express.js:164:17:164:41 | JSON.st ... .query) | provenance | | +| express.js:165:16:165:22 | myThing [ArrayElement] | express.js:165:16:165:22 | myThing | provenance | | | koa.js:6:6:6:27 | url | koa.js:7:15:7:17 | url | provenance | | | koa.js:6:6:6:27 | url | koa.js:8:18:8:20 | url | provenance | | | koa.js:6:6:6:27 | url | koa.js:14:16:14:18 | url | provenance | | @@ -62,6 +70,8 @@ nodes | express.js:83:16:83:34 | req.param("target") | semmle.label | req.param("target") | | express.js:90:18:90:23 | target | semmle.label | target | | express.js:97:16:97:21 | target | semmle.label | target | +| express.js:118:16:118:63 | [req.qu ... ection] | semmle.label | [req.qu ... ection] | +| express.js:118:16:118:63 | [req.qu ... ection] [0] | semmle.label | [req.qu ... ection] [0] | | express.js:118:16:118:72 | [req.qu ... oin('') | semmle.label | [req.qu ... oin('') | | express.js:118:17:118:30 | req.query.page | semmle.label | req.query.page | | express.js:134:16:134:36 | '/' + r ... ms.user | semmle.label | '/' + r ... ms.user | @@ -77,10 +87,13 @@ nodes | express.js:155:18:155:23 | target | semmle.label | target | | express.js:160:18:160:23 | target | semmle.label | target | | express.js:164:7:164:54 | myThing | semmle.label | myThing | +| express.js:164:7:164:54 | myThing [ArrayElement] | semmle.label | myThing [ArrayElement] | | express.js:164:17:164:41 | JSON.st ... .query) | semmle.label | JSON.st ... .query) | | express.js:164:17:164:54 | JSON.st ... (1, -1) | semmle.label | JSON.st ... (1, -1) | +| express.js:164:17:164:54 | JSON.st ... (1, -1) [ArrayElement] | semmle.label | JSON.st ... (1, -1) [ArrayElement] | | express.js:164:32:164:40 | req.query | semmle.label | req.query | | express.js:165:16:165:22 | myThing | semmle.label | myThing | +| express.js:165:16:165:22 | myThing [ArrayElement] | semmle.label | myThing [ArrayElement] | | koa.js:6:6:6:27 | url | semmle.label | url | | koa.js:6:12:6:27 | ctx.query.target | semmle.label | ctx.query.target | | koa.js:7:15:7:17 | url | semmle.label | url | diff --git a/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected b/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected index 4a5af8a6e001..b6622ba3dbc9 100644 --- a/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected @@ -29,8 +29,11 @@ edges | RegExpInjection.js:33:12:33:14 | key | RegExpInjection.js:29:21:29:21 | s | provenance | | | RegExpInjection.js:34:12:34:19 | getKey() | RegExpInjection.js:29:21:29:21 | s | provenance | | | RegExpInjection.js:54:14:54:16 | key | RegExpInjection.js:54:14:54:27 | key.split(".") | provenance | | +| RegExpInjection.js:54:14:54:16 | key | RegExpInjection.js:54:14:54:27 | key.split(".") [ArrayElement] | provenance | | | RegExpInjection.js:54:14:54:27 | key.split(".") | RegExpInjection.js:54:14:54:42 | key.spl ... x => x) | provenance | | +| RegExpInjection.js:54:14:54:27 | key.split(".") [ArrayElement] | RegExpInjection.js:54:14:54:42 | key.spl ... x => x) [ArrayElement] | provenance | | | RegExpInjection.js:54:14:54:42 | key.spl ... x => x) | RegExpInjection.js:54:14:54:52 | key.spl ... in("-") | provenance | | +| RegExpInjection.js:54:14:54:42 | key.spl ... x => x) [ArrayElement] | RegExpInjection.js:54:14:54:52 | key.spl ... in("-") | provenance | | | RegExpInjection.js:60:31:60:56 | input | RegExpInjection.js:64:14:64:18 | input | provenance | | | RegExpInjection.js:60:39:60:56 | req.param("input") | RegExpInjection.js:60:31:60:56 | input | provenance | | | RegExpInjection.js:82:7:82:32 | input | RegExpInjection.js:87:25:87:29 | input | provenance | | @@ -74,7 +77,9 @@ nodes | RegExpInjection.js:47:26:47:30 | input | semmle.label | input | | RegExpInjection.js:54:14:54:16 | key | semmle.label | key | | RegExpInjection.js:54:14:54:27 | key.split(".") | semmle.label | key.split(".") | +| RegExpInjection.js:54:14:54:27 | key.split(".") [ArrayElement] | semmle.label | key.split(".") [ArrayElement] | | RegExpInjection.js:54:14:54:42 | key.spl ... x => x) | semmle.label | key.spl ... x => x) | +| RegExpInjection.js:54:14:54:42 | key.spl ... x => x) [ArrayElement] | semmle.label | key.spl ... x => x) [ArrayElement] | | RegExpInjection.js:54:14:54:52 | key.spl ... in("-") | semmle.label | key.spl ... in("-") | | RegExpInjection.js:60:31:60:56 | input | semmle.label | input | | RegExpInjection.js:60:39:60:56 | req.param("input") | semmle.label | req.param("input") | diff --git a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/PrototypePollutingFunction.expected b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/PrototypePollutingFunction.expected index 1c21a6995335..77719fd65c7a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/PrototypePollutingFunction.expected +++ b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/PrototypePollutingFunction.expected @@ -97,8 +97,12 @@ nodes | tests.js:18:24:18:31 | src[key] | semmle.label | src[key] | | tests.js:18:28:18:30 | key | semmle.label | key | | tests.js:23:19:23:21 | dst | semmle.label | dst | +| tests.js:23:27:23:33 | sources [0] | semmle.label | sources [0] | +| tests.js:24:14:24:19 | source | semmle.label | source | +| tests.js:24:24:24:30 | sources [0] | semmle.label | sources [0] | | tests.js:25:18:25:20 | key | semmle.label | key | | tests.js:26:25:26:27 | dst | semmle.label | dst | +| tests.js:26:30:26:35 | source | semmle.label | source | | tests.js:26:30:26:40 | source[key] | semmle.label | source[key] | | tests.js:26:37:26:39 | key | semmle.label | key | | tests.js:26:43:26:45 | key | semmle.label | key | @@ -110,6 +114,7 @@ nodes | tests.js:32:20:32:27 | dst[key] | semmle.label | dst[key] | | tests.js:32:24:32:26 | key | semmle.label | key | | tests.js:34:18:34:25 | dstValue | semmle.label | dstValue | +| tests.js:34:28:34:32 | value | semmle.label | value | | tests.js:36:9:36:11 | dst | semmle.label | dst | | tests.js:36:13:36:15 | key | semmle.label | key | | tests.js:36:20:36:24 | value | semmle.label | value | @@ -567,8 +572,24 @@ nodes | tests.js:516:36:516:38 | key | semmle.label | key | | tests.js:517:35:517:37 | dst | semmle.label | dst | | tests.js:517:40:517:42 | key | semmle.label | key | +| tests.js:522:35:522:38 | args [0] | semmle.label | args [0] | +| tests.js:522:35:522:38 | args [1] | semmle.label | args [1] | +| tests.js:523:11:523:23 | dst | semmle.label | dst | +| tests.js:523:17:523:20 | args [0] | semmle.label | args [0] | +| tests.js:523:17:523:23 | args[0] | semmle.label | args[0] | +| tests.js:524:11:524:23 | src | semmle.label | src | +| tests.js:524:17:524:20 | args [1] | semmle.label | args [1] | +| tests.js:524:17:524:23 | args[1] | semmle.label | args[1] | | tests.js:525:14:525:16 | key | semmle.label | key | +| tests.js:527:35:527:37 | dst | semmle.label | dst | +| tests.js:527:35:527:42 | dst[key] | semmle.label | dst[key] | +| tests.js:527:39:527:41 | key | semmle.label | key | +| tests.js:527:45:527:47 | src | semmle.label | src | +| tests.js:527:45:527:52 | src[key] | semmle.label | src[key] | +| tests.js:527:49:527:51 | key | semmle.label | key | +| tests.js:529:13:529:15 | dst | semmle.label | dst | | tests.js:529:17:529:19 | key | semmle.label | key | +| tests.js:529:24:529:26 | src | semmle.label | src | | tests.js:529:24:529:31 | src[key] | semmle.label | src[key] | | tests.js:529:28:529:30 | key | semmle.label | key | | tests.js:534:31:534:33 | obj | semmle.label | obj | @@ -735,14 +756,19 @@ edges | tests.js:18:24:18:26 | src | tests.js:18:24:18:31 | src[key] | provenance | Config | | tests.js:18:28:18:30 | key | tests.js:18:24:18:31 | src[key] | provenance | Config | | tests.js:23:19:23:21 | dst | tests.js:26:25:26:27 | dst | provenance | | +| tests.js:23:27:23:33 | sources [0] | tests.js:24:24:24:30 | sources [0] | provenance | | +| tests.js:24:14:24:19 | source | tests.js:26:30:26:35 | source | provenance | | +| tests.js:24:24:24:30 | sources [0] | tests.js:24:14:24:19 | source | provenance | | | tests.js:25:18:25:20 | key | tests.js:26:37:26:39 | key | provenance | | | tests.js:25:18:25:20 | key | tests.js:26:43:26:45 | key | provenance | | | tests.js:26:25:26:27 | dst | tests.js:31:22:31:24 | dst | provenance | | +| tests.js:26:30:26:35 | source | tests.js:26:30:26:40 | source[key] | provenance | Config | | tests.js:26:30:26:40 | source[key] | tests.js:31:27:31:31 | value | provenance | | | tests.js:26:37:26:39 | key | tests.js:26:30:26:40 | source[key] | provenance | Config | | tests.js:26:43:26:45 | key | tests.js:31:34:31:36 | key | provenance | | | tests.js:31:22:31:24 | dst | tests.js:32:20:32:22 | dst | provenance | | | tests.js:31:22:31:24 | dst | tests.js:36:9:36:11 | dst | provenance | | +| tests.js:31:27:31:31 | value | tests.js:34:28:34:32 | value | provenance | | | tests.js:31:27:31:31 | value | tests.js:36:20:36:24 | value | provenance | | | tests.js:31:34:31:36 | key | tests.js:32:24:32:26 | key | provenance | | | tests.js:31:34:31:36 | key | tests.js:36:13:36:15 | key | provenance | | @@ -751,6 +777,7 @@ edges | tests.js:32:20:32:27 | dst[key] | tests.js:32:9:32:27 | dstValue | provenance | | | tests.js:32:24:32:26 | key | tests.js:32:20:32:27 | dst[key] | provenance | Config | | tests.js:34:18:34:25 | dstValue | tests.js:23:19:23:21 | dst | provenance | | +| tests.js:34:28:34:32 | value | tests.js:23:27:23:33 | sources [0] | provenance | | | tests.js:40:27:40:29 | dst | tests.js:44:30:44:32 | dst | provenance | | | tests.js:40:27:40:29 | dst | tests.js:46:13:46:15 | dst | provenance | | | tests.js:40:32:40:34 | src | tests.js:44:40:44:42 | src | provenance | | @@ -1257,8 +1284,27 @@ edges | tests.js:513:47:513:49 | key | tests.js:513:43:513:50 | src[key] | provenance | Config | | tests.js:516:32:516:34 | src | tests.js:516:32:516:39 | src[key] | provenance | Config | | tests.js:516:36:516:38 | key | tests.js:516:32:516:39 | src[key] | provenance | Config | +| tests.js:522:35:522:38 | args [0] | tests.js:523:17:523:20 | args [0] | provenance | | +| tests.js:522:35:522:38 | args [1] | tests.js:524:17:524:20 | args [1] | provenance | | +| tests.js:523:11:523:23 | dst | tests.js:527:35:527:37 | dst | provenance | | +| tests.js:523:11:523:23 | dst | tests.js:529:13:529:15 | dst | provenance | | +| tests.js:523:17:523:20 | args [0] | tests.js:523:17:523:23 | args[0] | provenance | | +| tests.js:523:17:523:23 | args[0] | tests.js:523:11:523:23 | dst | provenance | | +| tests.js:524:11:524:23 | src | tests.js:527:45:527:47 | src | provenance | | +| tests.js:524:11:524:23 | src | tests.js:529:24:529:26 | src | provenance | | +| tests.js:524:17:524:20 | args [1] | tests.js:524:17:524:23 | args[1] | provenance | | +| tests.js:524:17:524:23 | args[1] | tests.js:524:11:524:23 | src | provenance | | +| tests.js:525:14:525:16 | key | tests.js:527:39:527:41 | key | provenance | | +| tests.js:525:14:525:16 | key | tests.js:527:49:527:51 | key | provenance | | | tests.js:525:14:525:16 | key | tests.js:529:17:529:19 | key | provenance | | | tests.js:525:14:525:16 | key | tests.js:529:28:529:30 | key | provenance | | +| tests.js:527:35:527:37 | dst | tests.js:527:35:527:42 | dst[key] | provenance | Config | +| tests.js:527:35:527:42 | dst[key] | tests.js:522:35:522:38 | args [0] | provenance | | +| tests.js:527:39:527:41 | key | tests.js:527:35:527:42 | dst[key] | provenance | Config | +| tests.js:527:45:527:47 | src | tests.js:527:45:527:52 | src[key] | provenance | Config | +| tests.js:527:45:527:52 | src[key] | tests.js:522:35:522:38 | args [1] | provenance | | +| tests.js:527:49:527:51 | key | tests.js:527:45:527:52 | src[key] | provenance | Config | +| tests.js:529:24:529:26 | src | tests.js:529:24:529:31 | src[key] | provenance | Config | | tests.js:529:28:529:30 | key | tests.js:529:24:529:31 | src[key] | provenance | Config | | tests.js:534:31:534:33 | obj | tests.js:538:27:538:29 | obj | provenance | | | tests.js:534:36:534:43 | callback [dst] | tests.js:538:9:538:16 | callback [dst] | provenance | | @@ -1371,5 +1417,6 @@ subpaths | tests.js:477:13:477:15 | dst | tests.js:473:25:473:27 | key | tests.js:477:13:477:15 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | tests.js:473:12:473:14 | src | src | tests.js:477:13:477:15 | dst | dst | | tests.js:489:13:489:15 | dst | tests.js:484:14:484:16 | key | tests.js:489:13:489:15 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | tests.js:484:21:484:23 | src | src | tests.js:489:13:489:15 | dst | dst | | tests.js:517:35:517:37 | dst | tests.js:511:19:511:25 | keys[i] | tests.js:517:35:517:37 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | tests.js:509:28:509:30 | src | src | tests.js:517:35:517:37 | dst | dst | +| tests.js:529:13:529:15 | dst | tests.js:525:14:525:16 | key | tests.js:529:13:529:15 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | tests.js:525:21:525:23 | src | src | tests.js:529:13:529:15 | dst | dst | | tests.js:547:13:547:15 | dst | tests.js:538:18:538:24 | keys[i] | tests.js:547:13:547:15 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | tests.js:535:30:535:32 | obj | obj | tests.js:547:13:547:15 | dst | dst | | tests.js:605:13:605:16 | dest | tests.js:601:16:601:18 | key | tests.js:605:13:605:16 | dest | Properties are copied from $@ to $@ without guarding against prototype pollution. | tests.js:601:35:601:40 | source | source | tests.js:605:13:605:16 | dest | dest | From 837a8be1b8de3ff08a799534d21ab70a3304956f Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 27 Aug 2024 11:31:02 +0200 Subject: [PATCH 27/37] JS: Update test output and add related TODO in 'markdown-table' model --- .../semmle/javascript/frameworks/Markdown.qll | 1 + .../ReflectedXss/ReflectedXss.expected | 36 ++++++++++++++----- .../CWE-079/ReflectedXss/ReflectedXss.js | 2 +- .../ReflectedXssWithCustomSanitizer.expected | 1 - 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Markdown.qll b/javascript/ql/lib/semmle/javascript/frameworks/Markdown.qll index fa8fd4da5656..04f3c9f7db78 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Markdown.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Markdown.qll @@ -52,6 +52,7 @@ module Markdown { private class MarkdownTableStep extends MarkdownStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { exists(DataFlow::CallNode call | call = DataFlow::moduleImport("markdown-table").getACall() | + // TODO: needs a flow summary to ensure ArrayElement content is unfolded succ = call and pred = call.getArgument(0) ) diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected index c8e90d807375..ac9d399bd967 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected @@ -2,9 +2,6 @@ edges | ReflectedXss.js:8:33:8:45 | req.params.id | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | provenance | | | ReflectedXss.js:17:31:17:39 | params.id | ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | provenance | | | ReflectedXss.js:23:19:23:26 | req.body | ReflectedXss.js:23:12:23:27 | marked(req.body) | provenance | | -| ReflectedXss.js:30:7:33:4 | mytable | ReflectedXss.js:34:12:34:18 | mytable | provenance | | -| ReflectedXss.js:30:17:33:4 | table([ ... y]\\n ]) | ReflectedXss.js:30:7:33:4 | mytable | provenance | | -| ReflectedXss.js:32:14:32:21 | req.body | ReflectedXss.js:30:17:33:4 | table([ ... y]\\n ]) | provenance | | | ReflectedXss.js:42:31:42:38 | req.body | ReflectedXss.js:42:12:42:39 | convert ... q.body) | provenance | | | ReflectedXss.js:64:14:64:21 | req.body | ReflectedXss.js:64:39:64:42 | file | provenance | | | ReflectedXss.js:64:39:64:42 | file | ReflectedXss.js:65:16:65:19 | file | provenance | | @@ -26,12 +23,18 @@ edges | ReflectedXss.js:116:18:116:26 | queryKeys | ReflectedXss.js:116:11:116:45 | keys | provenance | | | ReflectedXss.js:116:31:116:45 | paramKeys?.keys | ReflectedXss.js:116:11:116:45 | keys | provenance | | | ReflectedXss.js:118:11:118:61 | keyArray | ReflectedXss.js:119:25:119:32 | keyArray | provenance | | -| ReflectedXss.js:118:50:118:53 | keys | ReflectedXss.js:118:11:118:61 | keyArray | provenance | | +| ReflectedXss.js:118:11:118:61 | keyArray [0] | ReflectedXss.js:119:25:119:32 | keyArray [0] | provenance | | +| ReflectedXss.js:118:49:118:54 | [keys] [0] | ReflectedXss.js:118:11:118:61 | keyArray [0] | provenance | | +| ReflectedXss.js:118:50:118:53 | keys | ReflectedXss.js:118:49:118:54 | [keys] [0] | provenance | | | ReflectedXss.js:118:58:118:61 | keys | ReflectedXss.js:118:11:118:61 | keyArray | provenance | | | ReflectedXss.js:119:11:119:72 | invalidKeys | ReflectedXss.js:122:33:122:43 | invalidKeys | provenance | | +| ReflectedXss.js:119:11:119:72 | invalidKeys [0] | ReflectedXss.js:122:33:122:43 | invalidKeys [0] | provenance | | | ReflectedXss.js:119:25:119:32 | keyArray | ReflectedXss.js:119:25:119:72 | keyArra ... s(key)) | provenance | | +| ReflectedXss.js:119:25:119:32 | keyArray [0] | ReflectedXss.js:119:25:119:72 | keyArra ... s(key)) [0] | provenance | | | ReflectedXss.js:119:25:119:72 | keyArra ... s(key)) | ReflectedXss.js:119:11:119:72 | invalidKeys | provenance | | +| ReflectedXss.js:119:25:119:72 | keyArra ... s(key)) [0] | ReflectedXss.js:119:11:119:72 | invalidKeys [0] | provenance | | | ReflectedXss.js:122:33:122:43 | invalidKeys | ReflectedXss.js:122:33:122:54 | invalid ... n(', ') | provenance | | +| ReflectedXss.js:122:33:122:43 | invalidKeys [0] | ReflectedXss.js:122:33:122:54 | invalid ... n(', ') | provenance | | | ReflectedXss.js:122:33:122:54 | invalid ... n(', ') | ReflectedXss.js:122:30:122:73 | `${inva ... telist` | provenance | | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | provenance | | | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | provenance | | @@ -40,14 +43,22 @@ edges | ReflectedXssGood3.js:68:22:68:26 | value | ReflectedXssGood3.js:77:16:77:20 | value | provenance | | | ReflectedXssGood3.js:68:22:68:26 | value | ReflectedXssGood3.js:105:18:105:22 | value | provenance | | | ReflectedXssGood3.js:77:7:77:37 | parts | ReflectedXssGood3.js:108:10:108:14 | parts | provenance | | +| ReflectedXssGood3.js:77:7:77:37 | parts [0] | ReflectedXssGood3.js:108:10:108:14 | parts [0] | provenance | | +| ReflectedXssGood3.js:77:7:77:37 | parts [ArrayElement] | ReflectedXssGood3.js:108:10:108:14 | parts [ArrayElement] | provenance | | +| ReflectedXssGood3.js:77:15:77:37 | [value. ... (0, i)] [0] | ReflectedXssGood3.js:77:7:77:37 | parts [0] | provenance | | | ReflectedXssGood3.js:77:16:77:20 | value | ReflectedXssGood3.js:77:16:77:36 | value.s ... g(0, i) | provenance | | | ReflectedXssGood3.js:77:16:77:36 | value.s ... g(0, i) | ReflectedXssGood3.js:77:7:77:37 | parts | provenance | | +| ReflectedXssGood3.js:77:16:77:36 | value.s ... g(0, i) | ReflectedXssGood3.js:77:15:77:37 | [value. ... (0, i)] [0] | provenance | | | ReflectedXssGood3.js:77:16:77:36 | value.s ... g(0, i) | ReflectedXssGood3.js:108:10:108:23 | parts.join('') | provenance | | | ReflectedXssGood3.js:105:7:105:11 | [post update] parts | ReflectedXssGood3.js:77:7:77:37 | parts | provenance | | | ReflectedXssGood3.js:105:7:105:11 | [post update] parts | ReflectedXssGood3.js:108:10:108:23 | parts.join('') | provenance | | +| ReflectedXssGood3.js:105:7:105:11 | [post update] parts [ArrayElement] | ReflectedXssGood3.js:77:7:77:37 | parts [ArrayElement] | provenance | | | ReflectedXssGood3.js:105:18:105:22 | value | ReflectedXssGood3.js:105:18:105:38 | value.s ... g(j, i) | provenance | | | ReflectedXssGood3.js:105:18:105:38 | value.s ... g(j, i) | ReflectedXssGood3.js:105:7:105:11 | [post update] parts | provenance | | +| ReflectedXssGood3.js:105:18:105:38 | value.s ... g(j, i) | ReflectedXssGood3.js:105:7:105:11 | [post update] parts [ArrayElement] | provenance | | | ReflectedXssGood3.js:108:10:108:14 | parts | ReflectedXssGood3.js:108:10:108:23 | parts.join('') | provenance | | +| ReflectedXssGood3.js:108:10:108:14 | parts [0] | ReflectedXssGood3.js:108:10:108:23 | parts.join('') | provenance | | +| ReflectedXssGood3.js:108:10:108:14 | parts [ArrayElement] | ReflectedXssGood3.js:108:10:108:23 | parts.join('') | provenance | | | ReflectedXssGood3.js:135:9:135:27 | url | ReflectedXssGood3.js:139:24:139:26 | url | provenance | | | ReflectedXssGood3.js:135:15:135:27 | req.params.id | ReflectedXssGood3.js:135:9:135:27 | url | provenance | | | ReflectedXssGood3.js:139:24:139:26 | url | ReflectedXssGood3.js:68:22:68:26 | value | provenance | | @@ -149,10 +160,6 @@ nodes | ReflectedXss.js:23:12:23:27 | marked(req.body) | semmle.label | marked(req.body) | | ReflectedXss.js:23:19:23:26 | req.body | semmle.label | req.body | | ReflectedXss.js:29:12:29:19 | req.body | semmle.label | req.body | -| ReflectedXss.js:30:7:33:4 | mytable | semmle.label | mytable | -| ReflectedXss.js:30:17:33:4 | table([ ... y]\\n ]) | semmle.label | table([ ... y]\\n ]) | -| ReflectedXss.js:32:14:32:21 | req.body | semmle.label | req.body | -| ReflectedXss.js:34:12:34:18 | mytable | semmle.label | mytable | | ReflectedXss.js:41:12:41:19 | req.body | semmle.label | req.body | | ReflectedXss.js:42:12:42:39 | convert ... q.body) | semmle.label | convert ... q.body) | | ReflectedXss.js:42:31:42:38 | req.body | semmle.label | req.body | @@ -188,13 +195,19 @@ nodes | ReflectedXss.js:116:18:116:26 | queryKeys | semmle.label | queryKeys | | ReflectedXss.js:116:31:116:45 | paramKeys?.keys | semmle.label | paramKeys?.keys | | ReflectedXss.js:118:11:118:61 | keyArray | semmle.label | keyArray | +| ReflectedXss.js:118:11:118:61 | keyArray [0] | semmle.label | keyArray [0] | +| ReflectedXss.js:118:49:118:54 | [keys] [0] | semmle.label | [keys] [0] | | ReflectedXss.js:118:50:118:53 | keys | semmle.label | keys | | ReflectedXss.js:118:58:118:61 | keys | semmle.label | keys | | ReflectedXss.js:119:11:119:72 | invalidKeys | semmle.label | invalidKeys | +| ReflectedXss.js:119:11:119:72 | invalidKeys [0] | semmle.label | invalidKeys [0] | | ReflectedXss.js:119:25:119:32 | keyArray | semmle.label | keyArray | +| ReflectedXss.js:119:25:119:32 | keyArray [0] | semmle.label | keyArray [0] | | ReflectedXss.js:119:25:119:72 | keyArra ... s(key)) | semmle.label | keyArra ... s(key)) | +| ReflectedXss.js:119:25:119:72 | keyArra ... s(key)) [0] | semmle.label | keyArra ... s(key)) [0] | | ReflectedXss.js:122:30:122:73 | `${inva ... telist` | semmle.label | `${inva ... telist` | | ReflectedXss.js:122:33:122:43 | invalidKeys | semmle.label | invalidKeys | +| ReflectedXss.js:122:33:122:43 | invalidKeys [0] | semmle.label | invalidKeys [0] | | ReflectedXss.js:122:33:122:54 | invalid ... n(', ') | semmle.label | invalid ... n(', ') | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | semmle.label | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | semmle.label | req.params.id | @@ -206,12 +219,18 @@ nodes | ReflectedXssContentTypes.js:70:22:70:34 | req.params.id | semmle.label | req.params.id | | ReflectedXssGood3.js:68:22:68:26 | value | semmle.label | value | | ReflectedXssGood3.js:77:7:77:37 | parts | semmle.label | parts | +| ReflectedXssGood3.js:77:7:77:37 | parts [0] | semmle.label | parts [0] | +| ReflectedXssGood3.js:77:7:77:37 | parts [ArrayElement] | semmle.label | parts [ArrayElement] | +| ReflectedXssGood3.js:77:15:77:37 | [value. ... (0, i)] [0] | semmle.label | [value. ... (0, i)] [0] | | ReflectedXssGood3.js:77:16:77:20 | value | semmle.label | value | | ReflectedXssGood3.js:77:16:77:36 | value.s ... g(0, i) | semmle.label | value.s ... g(0, i) | | ReflectedXssGood3.js:105:7:105:11 | [post update] parts | semmle.label | [post update] parts | +| ReflectedXssGood3.js:105:7:105:11 | [post update] parts [ArrayElement] | semmle.label | [post update] parts [ArrayElement] | | ReflectedXssGood3.js:105:18:105:22 | value | semmle.label | value | | ReflectedXssGood3.js:105:18:105:38 | value.s ... g(j, i) | semmle.label | value.s ... g(j, i) | | ReflectedXssGood3.js:108:10:108:14 | parts | semmle.label | parts | +| ReflectedXssGood3.js:108:10:108:14 | parts [0] | semmle.label | parts [0] | +| ReflectedXssGood3.js:108:10:108:14 | parts [ArrayElement] | semmle.label | parts [ArrayElement] | | ReflectedXssGood3.js:108:10:108:23 | parts.join('') | semmle.label | parts.join('') | | ReflectedXssGood3.js:135:9:135:27 | url | semmle.label | url | | ReflectedXssGood3.js:135:15:135:27 | req.params.id | semmle.label | req.params.id | @@ -335,7 +354,6 @@ subpaths | ReflectedXss.js:22:12:22:19 | req.body | ReflectedXss.js:22:12:22:19 | req.body | ReflectedXss.js:22:12:22:19 | req.body | Cross-site scripting vulnerability due to a $@. | ReflectedXss.js:22:12:22:19 | req.body | user-provided value | | ReflectedXss.js:23:12:23:27 | marked(req.body) | ReflectedXss.js:23:19:23:26 | req.body | ReflectedXss.js:23:12:23:27 | marked(req.body) | Cross-site scripting vulnerability due to a $@. | ReflectedXss.js:23:19:23:26 | req.body | user-provided value | | ReflectedXss.js:29:12:29:19 | req.body | ReflectedXss.js:29:12:29:19 | req.body | ReflectedXss.js:29:12:29:19 | req.body | Cross-site scripting vulnerability due to a $@. | ReflectedXss.js:29:12:29:19 | req.body | user-provided value | -| ReflectedXss.js:34:12:34:18 | mytable | ReflectedXss.js:32:14:32:21 | req.body | ReflectedXss.js:34:12:34:18 | mytable | Cross-site scripting vulnerability due to a $@. | ReflectedXss.js:32:14:32:21 | req.body | user-provided value | | ReflectedXss.js:41:12:41:19 | req.body | ReflectedXss.js:41:12:41:19 | req.body | ReflectedXss.js:41:12:41:19 | req.body | Cross-site scripting vulnerability due to a $@. | ReflectedXss.js:41:12:41:19 | req.body | user-provided value | | ReflectedXss.js:42:12:42:39 | convert ... q.body) | ReflectedXss.js:42:31:42:38 | req.body | ReflectedXss.js:42:12:42:39 | convert ... q.body) | Cross-site scripting vulnerability due to a $@. | ReflectedXss.js:42:31:42:38 | req.body | user-provided value | | ReflectedXss.js:56:12:56:19 | req.body | ReflectedXss.js:56:12:56:19 | req.body | ReflectedXss.js:56:12:56:19 | req.body | Cross-site scripting vulnerability due to a $@. | ReflectedXss.js:56:12:56:19 | req.body | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js index fc2e1abb8882..c3b1cbc2da8a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js @@ -31,7 +31,7 @@ app.get('/user/:id', function(req, res) { ['Name', 'Content'], ['body', req.body] ]); - res.send(mytable); // NOT OK + res.send(mytable); // NOT OK - FIXME: only works in OLD dataflow, add implicit reads before library-contributed taint steps }); var showdown = require('showdown'); diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected index a367f07307a5..d29b35203b80 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected @@ -3,7 +3,6 @@ | ReflectedXss.js:22:12:22:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:22:12:22:19 | req.body | user-provided value | | ReflectedXss.js:23:12:23:27 | marked(req.body) | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:23:19:23:26 | req.body | user-provided value | | ReflectedXss.js:29:12:29:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:29:12:29:19 | req.body | user-provided value | -| ReflectedXss.js:34:12:34:18 | mytable | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:32:14:32:21 | req.body | user-provided value | | ReflectedXss.js:41:12:41:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:41:12:41:19 | req.body | user-provided value | | ReflectedXss.js:42:12:42:39 | convert ... q.body) | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:42:31:42:38 | req.body | user-provided value | | ReflectedXss.js:56:12:56:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:56:12:56:19 | req.body | user-provided value | From a2d53c261bfbda691978aed9c62cccd2345816ec Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 26 Aug 2024 14:02:07 +0200 Subject: [PATCH 28/37] JS: Update test output and add related TODO in model of 'async' --- .../ql/lib/semmle/javascript/frameworks/AsyncPackage.qll | 2 +- .../frameworks/AsyncPackage/AsyncTaintTracking.expected | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/AsyncPackage.qll b/javascript/ql/lib/semmle/javascript/frameworks/AsyncPackage.qll index 26f5570bc146..4dc60d447653 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/AsyncPackage.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/AsyncPackage.qll @@ -142,7 +142,7 @@ module AsyncPackage { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { exists(DataFlow::FunctionNode iteratee, IterationCall call | iteratee = call.getIteratorCallback() and // Require a closure to avoid spurious call/return mismatch. - pred = call.getCollection() and + pred = call.getCollection() and // TODO: needs a flow summary to ensure ArrayElement content is unfolded succ = iteratee.getParameter(0) ) } diff --git a/javascript/ql/test/library-tests/frameworks/AsyncPackage/AsyncTaintTracking.expected b/javascript/ql/test/library-tests/frameworks/AsyncPackage/AsyncTaintTracking.expected index 50e18f938a56..168f5ec5ace4 100644 --- a/javascript/ql/test/library-tests/frameworks/AsyncPackage/AsyncTaintTracking.expected +++ b/javascript/ql/test/library-tests/frameworks/AsyncPackage/AsyncTaintTracking.expected @@ -1,10 +1,10 @@ legacyDataFlowDifference +| each.js:11:9:11:16 | source() | each.js:13:12:13:15 | item | only flow with OLD data flow library | +| map.js:10:13:10:20 | source() | map.js:12:14:12:17 | item | only flow with OLD data flow library | +| map.js:26:13:26:20 | source() | map.js:28:27:28:32 | result | only flow with OLD data flow library | +| sortBy.js:10:22:10:29 | source() | sortBy.js:12:27:12:32 | result | only flow with OLD data flow library | #select -| each.js:11:9:11:16 | source() | each.js:13:12:13:15 | item | -| map.js:10:13:10:20 | source() | map.js:12:14:12:17 | item | | map.js:20:19:20:26 | source() | map.js:23:27:23:32 | result | -| map.js:26:13:26:20 | source() | map.js:28:27:28:32 | result | -| sortBy.js:10:22:10:29 | source() | sortBy.js:12:27:12:32 | result | | waterfall.js:8:30:8:37 | source() | waterfall.js:11:12:11:16 | taint | | waterfall.js:8:30:8:37 | source() | waterfall.js:20:10:20:14 | taint | | waterfall.js:28:18:28:25 | source() | waterfall.js:39:10:39:12 | err | From cb5dbb919d55e1bac1fc3918bd87e7cdec87ae66 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 27 Aug 2024 11:33:32 +0200 Subject: [PATCH 29/37] JS: Update test to reflect implicit read flow has been fixed Shows the effect of https://github.com/github/codeql/pull/17262 --- .../library-tests/TaintTracking/BasicTaintTracking.expected | 2 -- .../library-tests/TaintTracking/use-use-after-implicit-read.js | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 2a1ca5c57f6b..42b7ea80e8d1 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -35,7 +35,6 @@ legacyDataFlowDifference | spread.js:4:15:4:22 | source() | spread.js:18:8:18:8 | y | only flow with NEW data flow library | | spread.js:4:15:4:22 | source() | spread.js:24:8:24:8 | y | only flow with NEW data flow library | | use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:15:10:15:10 | x | only flow with NEW data flow library | -| use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:16:10:16:10 | y | only flow with NEW data flow library | consistencyIssue | library-tests/TaintTracking/nested-props.js:20 | expected an alert, but found none | NOT OK - but not found | Consistency | | library-tests/TaintTracking/stringification-read-steps.js:17 | expected an alert, but found none | NOT OK | Consistency | @@ -297,7 +296,6 @@ flow | tst.js:2:13:2:20 | source() | tst.js:54:14:54:19 | unsafe | | use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:8:10:8:17 | captured | | use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:15:10:15:10 | x | -| use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:16:10:16:10 | y | | xml.js:5:18:5:25 | source() | xml.js:8:14:8:17 | text | | xml.js:12:17:12:24 | source() | xml.js:13:14:13:19 | result | | xml.js:23:18:23:25 | source() | xml.js:20:14:20:17 | attr | diff --git a/javascript/ql/test/library-tests/TaintTracking/use-use-after-implicit-read.js b/javascript/ql/test/library-tests/TaintTracking/use-use-after-implicit-read.js index 17c11b6a5055..73e433deb392 100644 --- a/javascript/ql/test/library-tests/TaintTracking/use-use-after-implicit-read.js +++ b/javascript/ql/test/library-tests/TaintTracking/use-use-after-implicit-read.js @@ -13,5 +13,5 @@ function f(x) { function g(x, y) { sink(x); // NOT OK - sink(y); // OK [INCONSISTENCY] - implicit read confuses array index + sink(y); // OK } From f65879eef10b35769b6fda8d62005f14b629a92d Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 27 Aug 2024 11:34:03 +0200 Subject: [PATCH 30/37] JS: Update a test that no longer fails --- javascript/ql/test/library-tests/TripleDot/tst.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/test/library-tests/TripleDot/tst.js b/javascript/ql/test/library-tests/TripleDot/tst.js index 1a0f000fd501..07bec92a92f6 100644 --- a/javascript/ql/test/library-tests/TripleDot/tst.js +++ b/javascript/ql/test/library-tests/TripleDot/tst.js @@ -133,7 +133,7 @@ function t13() { function target(x, y, ...rest) { sink(x); // $ SPURIOUS: hasTaintFlow=t13.1 sink(y); // $ hasTaintFlow=t13.1 - sink(rest); // $ MISSING: hasTaintFlow=t13.1 + sink(rest); // $ hasTaintFlow=t13.1 sink(rest[0]); // $ MISSING: hasTaintFlow=t13.1 } target("safe", ...source('t13.1')); From 65a36b0b3b4d7471f4d77601eb683ecdcebcdc54 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 29 Aug 2024 13:41:58 +0200 Subject: [PATCH 31/37] JS: Add regression test for argument position confusion --- .../Security/CWE-079/DomBasedXss/Xss.expected | 23 +++++++++++++++++++ .../XssWithAdditionalSources.expected | 20 ++++++++++++++++ .../tainted-url-suffix-arguments.js | 13 +++++++++++ 3 files changed, 56 insertions(+) create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tainted-url-suffix-arguments.js diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected index 99fd44617758..96aa177e4c22 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected @@ -330,6 +330,16 @@ nodes | string-manipulations.js:9:36:9:57 | documen ... on.href | semmle.label | documen ... on.href | | string-manipulations.js:10:16:10:45 | String( ... n.href) | semmle.label | String( ... n.href) | | string-manipulations.js:10:23:10:44 | documen ... on.href | semmle.label | documen ... on.href | +| tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | semmle.label | 'arguments' object of function foo [1] | +| tainted-url-suffix-arguments.js:3:14:3:14 | x | semmle.label | x | +| tainted-url-suffix-arguments.js:3:17:3:17 | y | semmle.label | y | +| tainted-url-suffix-arguments.js:3:20:3:20 | z | semmle.label | z | +| tainted-url-suffix-arguments.js:5:22:5:22 | x | semmle.label | x | +| tainted-url-suffix-arguments.js:6:22:6:22 | y | semmle.label | y | +| tainted-url-suffix-arguments.js:7:22:7:22 | z | semmle.label | z | +| tainted-url-suffix-arguments.js:11:11:11:36 | url | semmle.label | url | +| tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | semmle.label | window.location.href | +| tainted-url-suffix-arguments.js:12:17:12:19 | url | semmle.label | url | | tooltip.jsx:6:11:6:30 | source | semmle.label | source | | tooltip.jsx:6:20:6:30 | window.name | semmle.label | window.name | | tooltip.jsx:10:25:10:30 | source | semmle.label | source | @@ -949,6 +959,16 @@ edges | string-manipulations.js:9:36:9:57 | documen ... on.href | string-manipulations.js:9:16:9:58 | String. ... n.href) | provenance | Config | | string-manipulations.js:10:23:10:44 | documen ... on.href | string-manipulations.js:10:16:10:45 | String( ... n.href) | provenance | | | string-manipulations.js:10:23:10:44 | documen ... on.href | string-manipulations.js:10:16:10:45 | String( ... n.href) | provenance | Config | +| tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | tainted-url-suffix-arguments.js:3:14:3:14 | x | provenance | Config | +| tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | tainted-url-suffix-arguments.js:3:17:3:17 | y | provenance | Config | +| tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | tainted-url-suffix-arguments.js:3:20:3:20 | z | provenance | Config | +| tainted-url-suffix-arguments.js:3:14:3:14 | x | tainted-url-suffix-arguments.js:5:22:5:22 | x | provenance | | +| tainted-url-suffix-arguments.js:3:17:3:17 | y | tainted-url-suffix-arguments.js:6:22:6:22 | y | provenance | | +| tainted-url-suffix-arguments.js:3:20:3:20 | z | tainted-url-suffix-arguments.js:7:22:7:22 | z | provenance | | +| tainted-url-suffix-arguments.js:11:11:11:36 | url | tainted-url-suffix-arguments.js:12:17:12:19 | url | provenance | | +| tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | tainted-url-suffix-arguments.js:11:11:11:36 | url | provenance | | +| tainted-url-suffix-arguments.js:12:17:12:19 | url | tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | provenance | | +| tainted-url-suffix-arguments.js:12:17:12:19 | url | tainted-url-suffix-arguments.js:3:17:3:17 | y | provenance | | | tooltip.jsx:6:11:6:30 | source | tooltip.jsx:10:25:10:30 | source | provenance | | | tooltip.jsx:6:11:6:30 | source | tooltip.jsx:11:25:11:30 | source | provenance | | | tooltip.jsx:6:20:6:30 | window.name | tooltip.jsx:6:11:6:30 | source | provenance | | @@ -1378,6 +1398,9 @@ subpaths | string-manipulations.js:8:16:8:48 | documen ... mLeft() | string-manipulations.js:8:16:8:37 | documen ... on.href | string-manipulations.js:8:16:8:48 | documen ... mLeft() | Cross-site scripting vulnerability due to $@. | string-manipulations.js:8:16:8:37 | documen ... on.href | user-provided value | | string-manipulations.js:9:16:9:58 | String. ... n.href) | string-manipulations.js:9:36:9:57 | documen ... on.href | string-manipulations.js:9:16:9:58 | String. ... n.href) | Cross-site scripting vulnerability due to $@. | string-manipulations.js:9:36:9:57 | documen ... on.href | user-provided value | | string-manipulations.js:10:16:10:45 | String( ... n.href) | string-manipulations.js:10:23:10:44 | documen ... on.href | string-manipulations.js:10:16:10:45 | String( ... n.href) | Cross-site scripting vulnerability due to $@. | string-manipulations.js:10:23:10:44 | documen ... on.href | user-provided value | +| tainted-url-suffix-arguments.js:5:22:5:22 | x | tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | tainted-url-suffix-arguments.js:5:22:5:22 | x | Cross-site scripting vulnerability due to $@. | tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | user-provided value | +| tainted-url-suffix-arguments.js:6:22:6:22 | y | tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | tainted-url-suffix-arguments.js:6:22:6:22 | y | Cross-site scripting vulnerability due to $@. | tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | user-provided value | +| tainted-url-suffix-arguments.js:7:22:7:22 | z | tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | tainted-url-suffix-arguments.js:7:22:7:22 | z | Cross-site scripting vulnerability due to $@. | tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | user-provided value | | tooltip.jsx:10:25:10:30 | source | tooltip.jsx:6:20:6:30 | window.name | tooltip.jsx:10:25:10:30 | source | Cross-site scripting vulnerability due to $@. | tooltip.jsx:6:20:6:30 | window.name | user-provided value | | tooltip.jsx:11:25:11:30 | source | tooltip.jsx:6:20:6:30 | window.name | tooltip.jsx:11:25:11:30 | source | Cross-site scripting vulnerability due to $@. | tooltip.jsx:6:20:6:30 | window.name | user-provided value | | tooltip.jsx:18:51:18:59 | provide() | tooltip.jsx:22:20:22:30 | window.name | tooltip.jsx:18:51:18:59 | provide() | Cross-site scripting vulnerability due to $@. | tooltip.jsx:22:20:22:30 | window.name | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected index afd5effb4c39..4f908c6fe101 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected @@ -335,6 +335,16 @@ nodes | string-manipulations.js:9:36:9:57 | documen ... on.href | semmle.label | documen ... on.href | | string-manipulations.js:10:16:10:45 | String( ... n.href) | semmle.label | String( ... n.href) | | string-manipulations.js:10:23:10:44 | documen ... on.href | semmle.label | documen ... on.href | +| tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | semmle.label | 'arguments' object of function foo [1] | +| tainted-url-suffix-arguments.js:3:14:3:14 | x | semmle.label | x | +| tainted-url-suffix-arguments.js:3:17:3:17 | y | semmle.label | y | +| tainted-url-suffix-arguments.js:3:20:3:20 | z | semmle.label | z | +| tainted-url-suffix-arguments.js:5:22:5:22 | x | semmle.label | x | +| tainted-url-suffix-arguments.js:6:22:6:22 | y | semmle.label | y | +| tainted-url-suffix-arguments.js:7:22:7:22 | z | semmle.label | z | +| tainted-url-suffix-arguments.js:11:11:11:36 | url | semmle.label | url | +| tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | semmle.label | window.location.href | +| tainted-url-suffix-arguments.js:12:17:12:19 | url | semmle.label | url | | tooltip.jsx:6:11:6:30 | source | semmle.label | source | | tooltip.jsx:6:20:6:30 | window.name | semmle.label | window.name | | tooltip.jsx:10:25:10:30 | source | semmle.label | source | @@ -974,6 +984,16 @@ edges | string-manipulations.js:9:36:9:57 | documen ... on.href | string-manipulations.js:9:16:9:58 | String. ... n.href) | provenance | Config | | string-manipulations.js:10:23:10:44 | documen ... on.href | string-manipulations.js:10:16:10:45 | String( ... n.href) | provenance | | | string-manipulations.js:10:23:10:44 | documen ... on.href | string-manipulations.js:10:16:10:45 | String( ... n.href) | provenance | Config | +| tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | tainted-url-suffix-arguments.js:3:14:3:14 | x | provenance | Config | +| tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | tainted-url-suffix-arguments.js:3:17:3:17 | y | provenance | Config | +| tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | tainted-url-suffix-arguments.js:3:20:3:20 | z | provenance | Config | +| tainted-url-suffix-arguments.js:3:14:3:14 | x | tainted-url-suffix-arguments.js:5:22:5:22 | x | provenance | | +| tainted-url-suffix-arguments.js:3:17:3:17 | y | tainted-url-suffix-arguments.js:6:22:6:22 | y | provenance | | +| tainted-url-suffix-arguments.js:3:20:3:20 | z | tainted-url-suffix-arguments.js:7:22:7:22 | z | provenance | | +| tainted-url-suffix-arguments.js:11:11:11:36 | url | tainted-url-suffix-arguments.js:12:17:12:19 | url | provenance | | +| tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | tainted-url-suffix-arguments.js:11:11:11:36 | url | provenance | | +| tainted-url-suffix-arguments.js:12:17:12:19 | url | tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | provenance | | +| tainted-url-suffix-arguments.js:12:17:12:19 | url | tainted-url-suffix-arguments.js:3:17:3:17 | y | provenance | | | tooltip.jsx:6:11:6:30 | source | tooltip.jsx:10:25:10:30 | source | provenance | | | tooltip.jsx:6:11:6:30 | source | tooltip.jsx:11:25:11:30 | source | provenance | | | tooltip.jsx:6:20:6:30 | window.name | tooltip.jsx:6:11:6:30 | source | provenance | | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tainted-url-suffix-arguments.js b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tainted-url-suffix-arguments.js new file mode 100644 index 000000000000..c853b1ebfbcf --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tainted-url-suffix-arguments.js @@ -0,0 +1,13 @@ +import 'dummy'; + +function foo(x, y, z) { + arguments; // ensure 'arguments' are used + document.writeln(x); // OK [INCONSISTENCY] + document.writeln(y); // NOT OK + document.writeln(z); // OK [INCONSISTENCY] +} + +function bar() { + const url = window.location.href; + foo('safe', url, 'safe'); +} From 4568967a76ca7effed60693b001b2eff0ace89aa Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 29 Aug 2024 13:36:44 +0200 Subject: [PATCH 32/37] JS: Do not use legacy taint steps in TaintedUrlSuffix Tainted URL suffix steps are added as configuration-specific additional steps, which means implicit reads may occur before any of these steps. These steps accidentally included the legacy taint steps which include a step from 'arguments' to all positional parameters. Combined with the implicit read, arguments could escape their array index and flow to any parameter while in the tainted-url flow state. --- .../javascript/security/TaintedUrlSuffix.qll | 2 +- .../Security/CWE-079/DomBasedXss/Xss.expected | 18 ------------------ .../XssWithAdditionalSources.expected | 16 ---------------- .../tainted-url-suffix-arguments.js | 4 ++-- 4 files changed, 3 insertions(+), 37 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll b/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll index 68a4f1c8d8ea..683c5e19f4d4 100644 --- a/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll +++ b/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll @@ -54,7 +54,7 @@ module TaintedUrlSuffix { // Inherit all ordinary taint steps except `x -> x.p` steps srclbl = label() and dstlbl = label() and - TaintTracking::sharedTaintStep(src, dst) and + TaintTracking::AdditionalTaintStep::step(src, dst) and not isSafeLocationProp(dst) or // Transition from URL suffix to full taint when extracting the query/fragment part. diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected index 96aa177e4c22..69a9515da11b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected @@ -330,13 +330,8 @@ nodes | string-manipulations.js:9:36:9:57 | documen ... on.href | semmle.label | documen ... on.href | | string-manipulations.js:10:16:10:45 | String( ... n.href) | semmle.label | String( ... n.href) | | string-manipulations.js:10:23:10:44 | documen ... on.href | semmle.label | documen ... on.href | -| tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | semmle.label | 'arguments' object of function foo [1] | -| tainted-url-suffix-arguments.js:3:14:3:14 | x | semmle.label | x | | tainted-url-suffix-arguments.js:3:17:3:17 | y | semmle.label | y | -| tainted-url-suffix-arguments.js:3:20:3:20 | z | semmle.label | z | -| tainted-url-suffix-arguments.js:5:22:5:22 | x | semmle.label | x | | tainted-url-suffix-arguments.js:6:22:6:22 | y | semmle.label | y | -| tainted-url-suffix-arguments.js:7:22:7:22 | z | semmle.label | z | | tainted-url-suffix-arguments.js:11:11:11:36 | url | semmle.label | url | | tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | semmle.label | window.location.href | | tainted-url-suffix-arguments.js:12:17:12:19 | url | semmle.label | url | @@ -426,7 +421,6 @@ nodes | tst.js:64:25:64:48 | documen ... .search | semmle.label | documen ... .search | | tst.js:65:25:65:48 | documen ... .search | semmle.label | documen ... .search | | tst.js:68:16:68:20 | bar() | semmle.label | bar() | -| tst.js:70:1:70:27 | [,docum ... search] | semmle.label | [,docum ... search] | | tst.js:70:1:70:27 | [,docum ... search] [1] | semmle.label | [,docum ... search] [1] | | tst.js:70:3:70:26 | documen ... .search | semmle.label | documen ... .search | | tst.js:70:46:70:46 | x | semmle.label | x | @@ -959,15 +953,9 @@ edges | string-manipulations.js:9:36:9:57 | documen ... on.href | string-manipulations.js:9:16:9:58 | String. ... n.href) | provenance | Config | | string-manipulations.js:10:23:10:44 | documen ... on.href | string-manipulations.js:10:16:10:45 | String( ... n.href) | provenance | | | string-manipulations.js:10:23:10:44 | documen ... on.href | string-manipulations.js:10:16:10:45 | String( ... n.href) | provenance | Config | -| tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | tainted-url-suffix-arguments.js:3:14:3:14 | x | provenance | Config | -| tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | tainted-url-suffix-arguments.js:3:17:3:17 | y | provenance | Config | -| tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | tainted-url-suffix-arguments.js:3:20:3:20 | z | provenance | Config | -| tainted-url-suffix-arguments.js:3:14:3:14 | x | tainted-url-suffix-arguments.js:5:22:5:22 | x | provenance | | | tainted-url-suffix-arguments.js:3:17:3:17 | y | tainted-url-suffix-arguments.js:6:22:6:22 | y | provenance | | -| tainted-url-suffix-arguments.js:3:20:3:20 | z | tainted-url-suffix-arguments.js:7:22:7:22 | z | provenance | | | tainted-url-suffix-arguments.js:11:11:11:36 | url | tainted-url-suffix-arguments.js:12:17:12:19 | url | provenance | | | tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | tainted-url-suffix-arguments.js:11:11:11:36 | url | provenance | | -| tainted-url-suffix-arguments.js:12:17:12:19 | url | tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | provenance | | | tainted-url-suffix-arguments.js:12:17:12:19 | url | tainted-url-suffix-arguments.js:3:17:3:17 | y | provenance | | | tooltip.jsx:6:11:6:30 | source | tooltip.jsx:10:25:10:30 | source | provenance | | | tooltip.jsx:6:11:6:30 | source | tooltip.jsx:11:25:11:30 | source | provenance | | @@ -1053,11 +1041,7 @@ edges | tst.js:60:34:60:34 | s | tst.js:62:18:62:18 | s | provenance | | | tst.js:64:25:64:48 | documen ... .search | tst.js:60:34:60:34 | s | provenance | | | tst.js:65:25:65:48 | documen ... .search | tst.js:60:34:60:34 | s | provenance | | -| tst.js:70:1:70:27 | [,docum ... search] | tst.js:70:46:70:46 | x | provenance | | -| tst.js:70:1:70:27 | [,docum ... search] | tst.js:70:46:70:46 | x | provenance | Config | | tst.js:70:1:70:27 | [,docum ... search] [1] | tst.js:70:46:70:46 | x | provenance | | -| tst.js:70:1:70:27 | [,docum ... search] [1] | tst.js:70:46:70:46 | x | provenance | Config | -| tst.js:70:3:70:26 | documen ... .search | tst.js:70:1:70:27 | [,docum ... search] | provenance | Config | | tst.js:70:3:70:26 | documen ... .search | tst.js:70:1:70:27 | [,docum ... search] [1] | provenance | | | tst.js:70:46:70:46 | x | tst.js:73:20:73:20 | x | provenance | | | tst.js:107:7:107:44 | v | tst.js:110:18:110:18 | v | provenance | | @@ -1398,9 +1382,7 @@ subpaths | string-manipulations.js:8:16:8:48 | documen ... mLeft() | string-manipulations.js:8:16:8:37 | documen ... on.href | string-manipulations.js:8:16:8:48 | documen ... mLeft() | Cross-site scripting vulnerability due to $@. | string-manipulations.js:8:16:8:37 | documen ... on.href | user-provided value | | string-manipulations.js:9:16:9:58 | String. ... n.href) | string-manipulations.js:9:36:9:57 | documen ... on.href | string-manipulations.js:9:16:9:58 | String. ... n.href) | Cross-site scripting vulnerability due to $@. | string-manipulations.js:9:36:9:57 | documen ... on.href | user-provided value | | string-manipulations.js:10:16:10:45 | String( ... n.href) | string-manipulations.js:10:23:10:44 | documen ... on.href | string-manipulations.js:10:16:10:45 | String( ... n.href) | Cross-site scripting vulnerability due to $@. | string-manipulations.js:10:23:10:44 | documen ... on.href | user-provided value | -| tainted-url-suffix-arguments.js:5:22:5:22 | x | tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | tainted-url-suffix-arguments.js:5:22:5:22 | x | Cross-site scripting vulnerability due to $@. | tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | user-provided value | | tainted-url-suffix-arguments.js:6:22:6:22 | y | tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | tainted-url-suffix-arguments.js:6:22:6:22 | y | Cross-site scripting vulnerability due to $@. | tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | user-provided value | -| tainted-url-suffix-arguments.js:7:22:7:22 | z | tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | tainted-url-suffix-arguments.js:7:22:7:22 | z | Cross-site scripting vulnerability due to $@. | tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | user-provided value | | tooltip.jsx:10:25:10:30 | source | tooltip.jsx:6:20:6:30 | window.name | tooltip.jsx:10:25:10:30 | source | Cross-site scripting vulnerability due to $@. | tooltip.jsx:6:20:6:30 | window.name | user-provided value | | tooltip.jsx:11:25:11:30 | source | tooltip.jsx:6:20:6:30 | window.name | tooltip.jsx:11:25:11:30 | source | Cross-site scripting vulnerability due to $@. | tooltip.jsx:6:20:6:30 | window.name | user-provided value | | tooltip.jsx:18:51:18:59 | provide() | tooltip.jsx:22:20:22:30 | window.name | tooltip.jsx:18:51:18:59 | provide() | Cross-site scripting vulnerability due to $@. | tooltip.jsx:22:20:22:30 | window.name | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected index 4f908c6fe101..2523b19237ff 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected @@ -335,13 +335,8 @@ nodes | string-manipulations.js:9:36:9:57 | documen ... on.href | semmle.label | documen ... on.href | | string-manipulations.js:10:16:10:45 | String( ... n.href) | semmle.label | String( ... n.href) | | string-manipulations.js:10:23:10:44 | documen ... on.href | semmle.label | documen ... on.href | -| tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | semmle.label | 'arguments' object of function foo [1] | -| tainted-url-suffix-arguments.js:3:14:3:14 | x | semmle.label | x | | tainted-url-suffix-arguments.js:3:17:3:17 | y | semmle.label | y | -| tainted-url-suffix-arguments.js:3:20:3:20 | z | semmle.label | z | -| tainted-url-suffix-arguments.js:5:22:5:22 | x | semmle.label | x | | tainted-url-suffix-arguments.js:6:22:6:22 | y | semmle.label | y | -| tainted-url-suffix-arguments.js:7:22:7:22 | z | semmle.label | z | | tainted-url-suffix-arguments.js:11:11:11:36 | url | semmle.label | url | | tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | semmle.label | window.location.href | | tainted-url-suffix-arguments.js:12:17:12:19 | url | semmle.label | url | @@ -431,7 +426,6 @@ nodes | tst.js:64:25:64:48 | documen ... .search | semmle.label | documen ... .search | | tst.js:65:25:65:48 | documen ... .search | semmle.label | documen ... .search | | tst.js:68:16:68:20 | bar() | semmle.label | bar() | -| tst.js:70:1:70:27 | [,docum ... search] | semmle.label | [,docum ... search] | | tst.js:70:1:70:27 | [,docum ... search] [1] | semmle.label | [,docum ... search] [1] | | tst.js:70:3:70:26 | documen ... .search | semmle.label | documen ... .search | | tst.js:70:46:70:46 | x | semmle.label | x | @@ -984,15 +978,9 @@ edges | string-manipulations.js:9:36:9:57 | documen ... on.href | string-manipulations.js:9:16:9:58 | String. ... n.href) | provenance | Config | | string-manipulations.js:10:23:10:44 | documen ... on.href | string-manipulations.js:10:16:10:45 | String( ... n.href) | provenance | | | string-manipulations.js:10:23:10:44 | documen ... on.href | string-manipulations.js:10:16:10:45 | String( ... n.href) | provenance | Config | -| tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | tainted-url-suffix-arguments.js:3:14:3:14 | x | provenance | Config | -| tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | tainted-url-suffix-arguments.js:3:17:3:17 | y | provenance | Config | -| tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | tainted-url-suffix-arguments.js:3:20:3:20 | z | provenance | Config | -| tainted-url-suffix-arguments.js:3:14:3:14 | x | tainted-url-suffix-arguments.js:5:22:5:22 | x | provenance | | | tainted-url-suffix-arguments.js:3:17:3:17 | y | tainted-url-suffix-arguments.js:6:22:6:22 | y | provenance | | -| tainted-url-suffix-arguments.js:3:20:3:20 | z | tainted-url-suffix-arguments.js:7:22:7:22 | z | provenance | | | tainted-url-suffix-arguments.js:11:11:11:36 | url | tainted-url-suffix-arguments.js:12:17:12:19 | url | provenance | | | tainted-url-suffix-arguments.js:11:17:11:36 | window.location.href | tainted-url-suffix-arguments.js:11:11:11:36 | url | provenance | | -| tainted-url-suffix-arguments.js:12:17:12:19 | url | tainted-url-suffix-arguments.js:3:1:8:1 | 'arguments' object of function foo [1] | provenance | | | tainted-url-suffix-arguments.js:12:17:12:19 | url | tainted-url-suffix-arguments.js:3:17:3:17 | y | provenance | | | tooltip.jsx:6:11:6:30 | source | tooltip.jsx:10:25:10:30 | source | provenance | | | tooltip.jsx:6:11:6:30 | source | tooltip.jsx:11:25:11:30 | source | provenance | | @@ -1078,11 +1066,7 @@ edges | tst.js:60:34:60:34 | s | tst.js:62:18:62:18 | s | provenance | | | tst.js:64:25:64:48 | documen ... .search | tst.js:60:34:60:34 | s | provenance | | | tst.js:65:25:65:48 | documen ... .search | tst.js:60:34:60:34 | s | provenance | | -| tst.js:70:1:70:27 | [,docum ... search] | tst.js:70:46:70:46 | x | provenance | | -| tst.js:70:1:70:27 | [,docum ... search] | tst.js:70:46:70:46 | x | provenance | Config | | tst.js:70:1:70:27 | [,docum ... search] [1] | tst.js:70:46:70:46 | x | provenance | | -| tst.js:70:1:70:27 | [,docum ... search] [1] | tst.js:70:46:70:46 | x | provenance | Config | -| tst.js:70:3:70:26 | documen ... .search | tst.js:70:1:70:27 | [,docum ... search] | provenance | Config | | tst.js:70:3:70:26 | documen ... .search | tst.js:70:1:70:27 | [,docum ... search] [1] | provenance | | | tst.js:70:46:70:46 | x | tst.js:73:20:73:20 | x | provenance | | | tst.js:107:7:107:44 | v | tst.js:110:18:110:18 | v | provenance | | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tainted-url-suffix-arguments.js b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tainted-url-suffix-arguments.js index c853b1ebfbcf..a1feef0267a0 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tainted-url-suffix-arguments.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tainted-url-suffix-arguments.js @@ -2,9 +2,9 @@ import 'dummy'; function foo(x, y, z) { arguments; // ensure 'arguments' are used - document.writeln(x); // OK [INCONSISTENCY] + document.writeln(x); // OK document.writeln(y); // NOT OK - document.writeln(z); // OK [INCONSISTENCY] + document.writeln(z); // OK } function bar() { From 92bb4b3da87ba7cdad07c053a76bae897b493fe8 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 5 Sep 2024 11:32:07 +0200 Subject: [PATCH 33/37] JS: Address some comments from hvitved --- .../semmle/javascript/dataflow/internal/DataFlowPrivate.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll index 25fa75e0e711..9992495c1639 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll @@ -1052,7 +1052,7 @@ predicate simpleLocalFlowStep(Node node1, Node node2) { exists(Function f | // When the first parameter is a rest parameter, flow into the rest parameter as a local flow step // to ensure we preserve knowledge about array indices - (node1 = TStaticParameterArrayNode(f) or node1 = TDynamicParameterArrayNode(f)) + node1 = TStaticParameterArrayNode(f) or node1 = TDynamicParameterArrayNode(f) | // rest parameter at initial position exists(Parameter rest | @@ -1163,7 +1163,7 @@ predicate readStep(Node node1, ContentSet c, Node node2) { c = ContentSet::arrayElementUnknown() ) or - // Prepare to store spread arguments into the dynamic arguments array, when it isn't the initial spread argument + // Prepare to store spread arguments into the dynamic arguments array, when it isn't the initial argument exists(InvokeExpr invoke, int n, Expr argument, Content storeContent | invoke.getArgument(n).stripParens().(SpreadElement).getOperand() = argument and n > 0 and // n=0 is handled as a value step From 379c7ef20a6946590ceb4c0b30b0359ce7d9826b Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 5 Sep 2024 11:48:38 +0200 Subject: [PATCH 34/37] JS: Add test to show lack of unknown array element being propagated --- .../ql/test/library-tests/TripleDot/tst.js | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/javascript/ql/test/library-tests/TripleDot/tst.js b/javascript/ql/test/library-tests/TripleDot/tst.js index 07bec92a92f6..59bafd3187e9 100644 --- a/javascript/ql/test/library-tests/TripleDot/tst.js +++ b/javascript/ql/test/library-tests/TripleDot/tst.js @@ -138,3 +138,28 @@ function t13() { } target("safe", ...source('t13.1')); } + +function t14() { + function target(x, y, ...rest) { + sink(x); // $ hasValueFlow=t14.1 + sink(y); // $ hasValueFlow=t14.1 + sink(rest.pop()); // $ hasValueFlow=t14.1 + sink(rest); // $ hasTaintFlow=t14.1 + } + const args = new Array(Math.floor(Math.random() * 10)); + args.push(source('t14.1')); + target(...args); +} + +function t15() { + function target(safe, x, y, ...rest) { + sink(safe); // $ SPURIOUS: hasTaintFlow=t15.1 + sink(x); // $ MISSING: hasValueFlow=t15.1 SPURIOUS: hasTaintFlow=t15.1 + sink(y); // $ MISSING: hasValueFlow=t15.1 SPURIOUS: hasTaintFlow=t15.1 + sink(rest.pop()); // $ MISSING: hasValueFlow=t15.1 SPURIOUS: hasTaintFlow=t15.1 + sink(rest); // $ hasTaintFlow=t15.1 + } + const args = new Array(Math.floor(Math.random() * 10)); + args.push(source('t15.1')); + target('safe', ...args); +} From a9a8351cce586fde007b7b8087f0c968f77eb937 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 5 Sep 2024 12:01:25 +0200 Subject: [PATCH 35/37] JS: Fix one case of missing handling of unknown array index --- .../javascript/dataflow/internal/DataFlowPrivate.qll | 6 +++++- javascript/ql/test/library-tests/TripleDot/tst.js | 8 ++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll index 9992495c1639..d67ae91aeb8f 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll @@ -1173,7 +1173,11 @@ predicate readStep(Node node1, ContentSet c, Node node2) { then c = ContentSet::arrayElement() and // unknown start index when not the first spread operator storeContent.isUnknownArrayElement() - else storeContent.asArrayIndex() = n + c.asArrayIndex() + else ( + storeContent.asArrayIndex() = n + c.asArrayIndex() + or + storeContent.isUnknownArrayElement() and c.asSingleton() = storeContent + ) ) or exists(FlowSummaryNode parameter, ParameterPosition pos | diff --git a/javascript/ql/test/library-tests/TripleDot/tst.js b/javascript/ql/test/library-tests/TripleDot/tst.js index 59bafd3187e9..df941b481cfa 100644 --- a/javascript/ql/test/library-tests/TripleDot/tst.js +++ b/javascript/ql/test/library-tests/TripleDot/tst.js @@ -153,10 +153,10 @@ function t14() { function t15() { function target(safe, x, y, ...rest) { - sink(safe); // $ SPURIOUS: hasTaintFlow=t15.1 - sink(x); // $ MISSING: hasValueFlow=t15.1 SPURIOUS: hasTaintFlow=t15.1 - sink(y); // $ MISSING: hasValueFlow=t15.1 SPURIOUS: hasTaintFlow=t15.1 - sink(rest.pop()); // $ MISSING: hasValueFlow=t15.1 SPURIOUS: hasTaintFlow=t15.1 + sink(safe); // $ SPURIOUS: hasValueFlow=t15.1 + sink(x); // $ hasValueFlow=t15.1 + sink(y); // $ hasValueFlow=t15.1 + sink(rest.pop()); // $ hasValueFlow=t15.1 sink(rest); // $ hasTaintFlow=t15.1 } const args = new Array(Math.floor(Math.random() * 10)); From 1da68aac7367942ea4c84f028a95e01336b6396b Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 5 Sep 2024 13:29:28 +0200 Subject: [PATCH 36/37] JS: Benign test output change This happened as a result of the bugfix in the previous commit --- javascript/ql/test/library-tests/Arrays/DataFlow.expected | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/test/library-tests/Arrays/DataFlow.expected b/javascript/ql/test/library-tests/Arrays/DataFlow.expected index 21671a194645..3d8cfc8ac3b9 100644 --- a/javascript/ql/test/library-tests/Arrays/DataFlow.expected +++ b/javascript/ql/test/library-tests/Arrays/DataFlow.expected @@ -1,11 +1,11 @@ legacyDataFlowDifference -| arrays.js:2:16:2:23 | "source" | arrays.js:39:8:39:24 | arr4_spread.pop() | only flow with OLD data flow library | flow | arrays.js:2:16:2:23 | "source" | arrays.js:5:8:5:14 | obj.foo | | arrays.js:2:16:2:23 | "source" | arrays.js:11:10:11:15 | arr[i] | | arrays.js:2:16:2:23 | "source" | arrays.js:15:27:15:27 | e | | arrays.js:2:16:2:23 | "source" | arrays.js:16:23:16:23 | e | | arrays.js:2:16:2:23 | "source" | arrays.js:20:8:20:16 | arr.pop() | +| arrays.js:2:16:2:23 | "source" | arrays.js:39:8:39:24 | arr4_spread.pop() | | arrays.js:2:16:2:23 | "source" | arrays.js:61:10:61:10 | x | | arrays.js:2:16:2:23 | "source" | arrays.js:65:10:65:10 | x | | arrays.js:2:16:2:23 | "source" | arrays.js:69:10:69:10 | x | From fb9732a33fe91d8d5782909568b62a2add83d414 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 5 Sep 2024 13:44:54 +0200 Subject: [PATCH 37/37] JS: Add another test and TODO about an issue with constant array indices --- .../lib/semmle/javascript/dataflow/internal/Contents.qll | 5 ++++- javascript/ql/test/library-tests/TripleDot/tst.js | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/Contents.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/Contents.qll index a359ee0d1d5b..3ccff93d0202 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/Contents.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/Contents.qll @@ -255,7 +255,10 @@ module Public { Content asSingleton() { this = MkSingletonContent(result) } /** Gets the property name to be accessed. */ - PropertyName asPropertyName() { result = this.asSingleton().asPropertyName() } + PropertyName asPropertyName() { + // TODO: array indices should be mapped to a ContentSet that also reads from UnknownArrayElement + result = this.asSingleton().asPropertyName() + } /** Gets the array index to be accessed. */ int asArrayIndex() { result = this.asSingleton().asArrayIndex() } diff --git a/javascript/ql/test/library-tests/TripleDot/tst.js b/javascript/ql/test/library-tests/TripleDot/tst.js index df941b481cfa..8fce4285e5be 100644 --- a/javascript/ql/test/library-tests/TripleDot/tst.js +++ b/javascript/ql/test/library-tests/TripleDot/tst.js @@ -163,3 +163,12 @@ function t15() { args.push(source('t15.1')); target('safe', ...args); } + +function t16() { + let array = new Array(Math.floor(Math.random() * 10)) + array.push(source("t16.1")); + sink(array[0]); // $ MISSING: hasValueFlow=t16.1 SPURIOUS: hasTaintFlow=t16.1 + sink(array[1]); // $ MISSING: hasValueFlow=t16.1 SPURIOUS: hasTaintFlow=t16.1 + sink(array[2]); // $ MISSING: hasValueFlow=t16.1 SPURIOUS: hasTaintFlow=t16.1 + sink(array); // $ hasTaintFlow=t16.1 +}