From 55d4e7e742415295e8ed25b3fb3adc7284d66743 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 6 Sep 2024 13:43:18 +0200 Subject: [PATCH 01/25] JS: Use ArrayElementKnown when reading a constant array index --- .../javascript/dataflow/internal/DataFlowPrivate.qll | 7 ++++++- javascript/ql/test/library-tests/TripleDot/tst.js | 8 ++++---- 2 files changed, 10 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 d67ae91aeb8f..54deedf13b9c 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll @@ -1103,7 +1103,12 @@ predicate readStep(Node node1, ContentSet c, Node node2) { node1 = read.getBase() and node2 = read | - c.asPropertyName() = read.getPropertyName() + exists(PropertyName name | read.getPropertyName() = name | + not exists(name.asArrayIndex()) and + c = ContentSet::property(name) + or + c = ContentSet::arrayElementKnown(name.asArrayIndex()) + ) or not exists(read.getPropertyName()) and c = ContentSet::arrayElement() diff --git a/javascript/ql/test/library-tests/TripleDot/tst.js b/javascript/ql/test/library-tests/TripleDot/tst.js index 8fce4285e5be..6f776264e84f 100644 --- a/javascript/ql/test/library-tests/TripleDot/tst.js +++ b/javascript/ql/test/library-tests/TripleDot/tst.js @@ -134,7 +134,7 @@ function t13() { sink(x); // $ SPURIOUS: hasTaintFlow=t13.1 sink(y); // $ hasTaintFlow=t13.1 sink(rest); // $ hasTaintFlow=t13.1 - sink(rest[0]); // $ MISSING: hasTaintFlow=t13.1 + sink(rest[0]); // $ hasTaintFlow=t13.1 } target("safe", ...source('t13.1')); } @@ -167,8 +167,8 @@ function t15() { 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[0]); // $ hasValueFlow=t16.1 + sink(array[1]); // $ hasValueFlow=t16.1 + sink(array[2]); // $ hasValueFlow=t16.1 sink(array); // $ hasTaintFlow=t16.1 } From 013d226ae39dc81dc00cbcd03738fa8a222a1036 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 6 Sep 2024 13:46:26 +0200 Subject: [PATCH 02/25] JS: Update comment --- .../lib/semmle/javascript/dataflow/internal/Contents.qll | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/Contents.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/Contents.qll index 3ccff93d0202..fc86032c5024 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/Contents.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/Contents.qll @@ -254,11 +254,8 @@ module Public { /** Gets the singleton content to be accessed. */ Content asSingleton() { this = MkSingletonContent(result) } - /** Gets the property name to be accessed. */ - PropertyName asPropertyName() { - // TODO: array indices should be mapped to a ContentSet that also reads from UnknownArrayElement - result = this.asSingleton().asPropertyName() - } + /** Gets the property name to be accessed, provided that this is a singleton content set. */ + PropertyName asPropertyName() { result = this.asSingleton().asPropertyName() } /** Gets the array index to be accessed. */ int asArrayIndex() { result = this.asSingleton().asArrayIndex() } From 3d4287b7cc0dc4c9ca76bee820fd25c3444e52dd Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 6 Sep 2024 13:54:57 +0200 Subject: [PATCH 03/25] JS: Remove ContentSet#asArrayIndex() For ContentSet it is ambiguous whether asArrayIndex() should get a singleton content set, or the KnownArrayElement content set. The user will now have to choose between asSingleton().asArrayIndex() or ContentSet::arrayElementKnown. --- .../lib/semmle/javascript/dataflow/internal/Contents.qll | 3 --- .../javascript/dataflow/internal/DataFlowPrivate.qll | 8 ++++---- .../javascript/internal/flow_summaries/ForOfLoops.qll | 4 ++-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/Contents.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/Contents.qll index fc86032c5024..a915ef47d0f5 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/Contents.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/Contents.qll @@ -257,9 +257,6 @@ module Public { /** Gets the property name to be accessed, provided that this is a singleton content set. */ PropertyName asPropertyName() { result = this.asSingleton().asPropertyName() } - /** Gets the array index to be accessed. */ - int asArrayIndex() { result = this.asSingleton().asArrayIndex() } - /** * Gets a string representation of this content set. */ diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll index 54deedf13b9c..dc5b61821d7a 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll @@ -1162,7 +1162,7 @@ predicate readStep(Node node1, ContentSet c, Node node2) { node2 = TRestParameterStoreNode(function, content) | // shift known array indices - c.asArrayIndex() = content.asArrayIndex() + restIndex + c.asSingleton().asArrayIndex() = content.asArrayIndex() + restIndex or content.isUnknownArrayElement() and // TODO: don't read unknown array elements from static array c = ContentSet::arrayElementUnknown() @@ -1179,7 +1179,7 @@ predicate readStep(Node node1, ContentSet c, Node node2) { c = ContentSet::arrayElement() and // unknown start index when not the first spread operator storeContent.isUnknownArrayElement() else ( - storeContent.asArrayIndex() = n + c.asArrayIndex() + storeContent.asArrayIndex() = n + c.asSingleton().asArrayIndex() or storeContent.isUnknownArrayElement() and c.asSingleton() = storeContent ) @@ -1190,7 +1190,7 @@ predicate readStep(Node node1, ContentSet c, Node node2) { node1 = TFlowSummaryDynamicParameterArrayNode(parameter.getSummarizedCallable()) and node2 = parameter and ( - c.asArrayIndex() = pos.asPositional() + c.asSingleton().asArrayIndex() = pos.asPositional() or c = ContentSet::arrayElementLowerBound(pos.asPositionalLowerBound()) ) @@ -1261,7 +1261,7 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { exists(InvokeExpr invoke, int n | node1 = TValueNode(invoke.getArgument(n)) and node2 = TStaticArgumentArrayNode(invoke) and - c.asArrayIndex() = n and + c.asSingleton().asArrayIndex() = n and not n >= firstSpreadArgumentIndex(invoke) ) or diff --git a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/ForOfLoops.qll b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/ForOfLoops.qll index 1407ce7c79e5..ecc84170026f 100644 --- a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/ForOfLoops.qll +++ b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/ForOfLoops.qll @@ -48,10 +48,10 @@ class ForOfLoopStep extends AdditionalFlowInternal { ) { exists(ForOfStmt stmt | pred = getSynthesizedNode(stmt, "for-of-map-key") and - contents.asArrayIndex() = 0 + contents.asSingleton().asArrayIndex() = 0 or pred = getSynthesizedNode(stmt, "for-of-map-value") and - contents.asArrayIndex() = 1 + contents.asSingleton().asArrayIndex() = 1 | succ = DataFlow::lvalueNode(stmt.getLValue()) ) From e0ca1b04820ef56d12e8a74aa021866a74ee9993 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 10 Sep 2024 13:07:24 +0200 Subject: [PATCH 04/25] JS: Benign test updates --- javascript/ql/test/library-tests/Arrays/DataFlow.expected | 2 ++ javascript/ql/test/library-tests/Arrays/arrays.js | 2 +- javascript/ql/test/library-tests/FlowSummary/tst.js | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/javascript/ql/test/library-tests/Arrays/DataFlow.expected b/javascript/ql/test/library-tests/Arrays/DataFlow.expected index 3d8cfc8ac3b9..35a04acc4a1b 100644 --- a/javascript/ql/test/library-tests/Arrays/DataFlow.expected +++ b/javascript/ql/test/library-tests/Arrays/DataFlow.expected @@ -1,4 +1,5 @@ legacyDataFlowDifference +| arrays.js:2:16:2:23 | "source" | arrays.js:58:8:58:13 | arr[0] | only flow with NEW 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] | @@ -6,6 +7,7 @@ flow | 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 | | arrays.js:2:16:2:23 | "source" | arrays.js:69:10:69:10 | x | diff --git a/javascript/ql/test/library-tests/Arrays/arrays.js b/javascript/ql/test/library-tests/Arrays/arrays.js index 8c981a33a1f7..a994bd7bc57b 100644 --- a/javascript/ql/test/library-tests/Arrays/arrays.js +++ b/javascript/ql/test/library-tests/Arrays/arrays.js @@ -55,7 +55,7 @@ sink(ary); // OK - its the array itself, not an element. }); - sink(arr[0]); // OK - tuple like usage. + sink(arr[0]); // NOT OK for (const x of arr) { sink(x); // NOT OK diff --git a/javascript/ql/test/library-tests/FlowSummary/tst.js b/javascript/ql/test/library-tests/FlowSummary/tst.js index 264c304f0f31..f3bf8513840e 100644 --- a/javascript/ql/test/library-tests/FlowSummary/tst.js +++ b/javascript/ql/test/library-tests/FlowSummary/tst.js @@ -28,7 +28,7 @@ function m3() { function m4() { const flowIntoArrayElement = mkSummary("Argument[0]", "ReturnValue.ArrayElement"); sink(flowIntoArrayElement(source()).pop()); // NOT OK - sink(flowIntoArrayElement(source())[0]); // NOT OK [INCONSISTENCY] + sink(flowIntoArrayElement(source())[0]); // NOT OK sink(flowIntoArrayElement(source())[Math.random()]); // NOT OK sink(flowIntoArrayElement(source()).prop); // OK } From 0ddb1c87f57bb3a58c70d532114ed067ba98d880 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 10 Sep 2024 13:14:37 +0200 Subject: [PATCH 05/25] JS: Test update indicating a problem with .split() --- .../query-tests/Security/CWE-079/DomBasedXss/Xss.expected | 6 ++++++ .../CWE-079/DomBasedXss/XssWithAdditionalSources.expected | 5 +++++ .../ql/test/query-tests/Security/CWE-079/DomBasedXss/tst.js | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) 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 69a9515da11b..d6dc0b1b44ee 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 @@ -514,6 +514,9 @@ nodes | tst.js:371:7:371:39 | target | semmle.label | target | | tst.js:371:16:371:39 | documen ... .search | semmle.label | documen ... .search | | tst.js:374:18:374:23 | target | semmle.label | target | +| tst.js:377:18:377:39 | documen ... on.href | semmle.label | documen ... on.href | +| tst.js:377:18:377:50 | documen ... it("?") [ArrayElement] | semmle.label | documen ... it("?") [ArrayElement] | +| tst.js:377:18:377:53 | documen ... "?")[0] | semmle.label | documen ... "?")[0] | | tst.js:381:7:381:39 | target | semmle.label | target | | tst.js:381:7:381:39 | target [taint3] | semmle.label | target [taint3] | | tst.js:381:7:381:39 | target [taint8] | semmle.label | target [taint8] | @@ -1112,6 +1115,8 @@ edges | tst.js:355:19:355:42 | documen ... .search | tst.js:355:10:355:42 | target | provenance | | | tst.js:371:7:371:39 | target | tst.js:374:18:374:23 | target | provenance | | | tst.js:371:16:371:39 | documen ... .search | tst.js:371:7:371:39 | target | provenance | | +| tst.js:377:18:377:39 | documen ... on.href | tst.js:377:18:377:50 | documen ... it("?") [ArrayElement] | provenance | | +| tst.js:377:18:377:50 | documen ... it("?") [ArrayElement] | tst.js:377:18:377:53 | documen ... "?")[0] | provenance | | | tst.js:381:7:381:39 | target | tst.js:384:18:384:23 | target | provenance | | | tst.js:381:7:381:39 | target | tst.js:386:18:386:23 | target | provenance | | | tst.js:381:7:381:39 | target | tst.js:397:18:397:23 | target | provenance | | @@ -1455,6 +1460,7 @@ subpaths | tst.js:360:21:360:26 | target | tst.js:355:19:355:42 | documen ... .search | tst.js:360:21:360:26 | target | Cross-site scripting vulnerability due to $@. | tst.js:355:19:355:42 | documen ... .search | user-provided value | | tst.js:363:18:363:23 | target | tst.js:355:19:355:42 | documen ... .search | tst.js:363:18:363:23 | target | Cross-site scripting vulnerability due to $@. | tst.js:355:19:355:42 | documen ... .search | user-provided value | | tst.js:374:18:374:23 | target | tst.js:371:16:371:39 | documen ... .search | tst.js:374:18:374:23 | target | Cross-site scripting vulnerability due to $@. | tst.js:371:16:371:39 | documen ... .search | user-provided value | +| tst.js:377:18:377:53 | documen ... "?")[0] | tst.js:377:18:377:39 | documen ... on.href | tst.js:377:18:377:53 | documen ... "?")[0] | Cross-site scripting vulnerability due to $@. | tst.js:377:18:377:39 | documen ... on.href | user-provided value | | tst.js:384:18:384:23 | target | tst.js:381:16:381:39 | documen ... .search | tst.js:384:18:384:23 | target | Cross-site scripting vulnerability due to $@. | tst.js:381:16:381:39 | documen ... .search | user-provided value | | tst.js:386:18:386:29 | target.taint | tst.js:381:16:381:39 | documen ... .search | tst.js:386:18:386:29 | target.taint | Cross-site scripting vulnerability due to $@. | tst.js:381:16:381:39 | documen ... .search | user-provided value | | tst.js:392:18:392:30 | target.taint3 | tst.js:391:19:391:42 | documen ... .search | tst.js:392:18:392:30 | target.taint3 | Cross-site scripting vulnerability due to $@. | tst.js:391:19:391:42 | documen ... .search | 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 2523b19237ff..0390a90f7e9e 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 @@ -519,6 +519,9 @@ nodes | tst.js:371:7:371:39 | target | semmle.label | target | | tst.js:371:16:371:39 | documen ... .search | semmle.label | documen ... .search | | tst.js:374:18:374:23 | target | semmle.label | target | +| tst.js:377:18:377:39 | documen ... on.href | semmle.label | documen ... on.href | +| tst.js:377:18:377:50 | documen ... it("?") [ArrayElement] | semmle.label | documen ... it("?") [ArrayElement] | +| tst.js:377:18:377:53 | documen ... "?")[0] | semmle.label | documen ... "?")[0] | | tst.js:381:7:381:39 | target | semmle.label | target | | tst.js:381:7:381:39 | target [taint3] | semmle.label | target [taint3] | | tst.js:381:7:381:39 | target [taint8] | semmle.label | target [taint8] | @@ -1137,6 +1140,8 @@ edges | tst.js:355:19:355:42 | documen ... .search | tst.js:355:10:355:42 | target | provenance | | | tst.js:371:7:371:39 | target | tst.js:374:18:374:23 | target | provenance | | | tst.js:371:16:371:39 | documen ... .search | tst.js:371:7:371:39 | target | provenance | | +| tst.js:377:18:377:39 | documen ... on.href | tst.js:377:18:377:50 | documen ... it("?") [ArrayElement] | provenance | | +| tst.js:377:18:377:50 | documen ... it("?") [ArrayElement] | tst.js:377:18:377:53 | documen ... "?")[0] | provenance | | | tst.js:381:7:381:39 | target | tst.js:384:18:384:23 | target | provenance | | | tst.js:381:7:381:39 | target | tst.js:386:18:386:23 | target | provenance | | | tst.js:381:7:381:39 | target | tst.js:397:18:397:23 | target | provenance | | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tst.js b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tst.js index 3a8c59926451..1e42fa97fe24 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tst.js @@ -373,7 +373,7 @@ function test() { // NOT OK $('myId').html(target) - // OK + // OK [INCONSISTENCY] (TODO: fix) $('myid').html(document.location.href.split("?")[0]); } From 87454a4f113ed4ef90b36bd1de94c5965595e2f9 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 10 Sep 2024 14:44:49 +0200 Subject: [PATCH 06/25] JS: Remove unused predicate --- .../semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll | 3 --- 1 file changed, 3 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll index 3611d34667ea..63826e5878c3 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll @@ -124,9 +124,6 @@ string encodeArgumentPosition(ArgumentPosition pos) { /** Gets the return kind corresponding to specification `"ReturnValue"`. */ ReturnKind getStandardReturnValueKind() { result = MkNormalReturnKind() } -/** Gets the return kind corresponding to specification `"ReturnValue"`. */ -MkNormalReturnKind getReturnValueKind() { any() } - private module FlowSummaryStepInput implements Private::StepsInputSig { DataFlowCall getACall(SummarizedCallable sc) { exists(LibraryCallable callable | callable = sc | From 24983a5836198c09fda46b72b86471fe8bf1f08c Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 10 Sep 2024 14:59:39 +0200 Subject: [PATCH 07/25] JS: Add OptionalStep and OptionalBarrier MaD tokens OptionalStep[foo] and OptionalBarrier[foo] contribute steps/barriers that are not active by default, but can be opted into by specific queries or for specific flow states. (Will be used in the following commits) --- .../javascript/dataflow/internal/Contents.qll | 20 +++++++++++++++-- .../dataflow/internal/DataFlowPrivate.qll | 22 +++++++++++++++++++ .../dataflow/internal/FlowSummaryPrivate.qll | 4 ++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/Contents.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/Contents.qll index a915ef47d0f5..a87434239224 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/Contents.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/Contents.qll @@ -93,14 +93,20 @@ module Private { // than an ordinary content component. These special content sets should never appear in a step. MkAwaited() or MkAnyPropertyDeep() or - MkArrayElementDeep() + MkArrayElementDeep() or + MkOptionalStep(string name) { isAccessPathTokenPresent("OptionalStep", name) } or + MkOptionalBarrier(string name) { isAccessPathTokenPresent("OptionalBarrier", name) } /** * Holds if `cs` is used to encode a special operation as a content component, but should not * be treated as an ordinary content component. */ predicate isSpecialContentSet(ContentSet cs) { - cs = MkAwaited() or cs = MkAnyPropertyDeep() or cs = MkArrayElementDeep() + cs = MkAwaited() or + cs = MkAnyPropertyDeep() or + cs = MkArrayElementDeep() or + cs instanceof MkOptionalStep or + cs instanceof MkOptionalBarrier } } @@ -288,6 +294,16 @@ module Public { or this = MkAnyCapturedContent() and result = "AnyCapturedContent" + or + exists(string name | + this = MkOptionalStep(name) and + result = "OptionalStep[" + name + "]" + ) + or + exists(string name | + this = MkOptionalBarrier(name) and + result = "OptionalBarrier[" + name + "]" + ) } } diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll index dc5b61821d7a..f8f86e04c08e 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll @@ -1035,6 +1035,11 @@ predicate simpleLocalFlowStep(Node node1, Node node2) { FlowSummaryPrivate::Steps::summaryReadStep(input, MkAwaited(), output) and node1 = TFlowSummaryNode(input) and node2 = TFlowSummaryNode(output) + or + // Add flow through optional barriers. This step is then blocked by the barrier for queries that choose to use the barrier. + FlowSummaryPrivate::Steps::summaryReadStep(input, MkOptionalBarrier(_), output) and + node1 = TFlowSummaryNode(input) and + node2 = TFlowSummaryNode(output) ) or VariableCaptureOutput::localFlowStep(getClosureNode(node1), getClosureNode(node2)) @@ -1389,3 +1394,20 @@ class ArgumentNode extends DataFlow::Node { class ParameterNode extends DataFlow::Node { ParameterNode() { isParameterNodeImpl(this, _, _) } } + +cached +private module OptionalSteps { + cached + predicate optionalStep(Node node1, string name, Node node2) { + FlowSummaryPrivate::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), + MkOptionalStep(name), node2.(FlowSummaryNode).getSummaryNode()) + } + + cached + predicate optionalBarrier(Node node, string name) { + FlowSummaryPrivate::Steps::summaryReadStep(_, MkOptionalBarrier(name), + node.(FlowSummaryNode).getSummaryNode()) + } +} + +import OptionalSteps diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll index 63826e5878c3..e969ab39d37e 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll @@ -95,6 +95,10 @@ private string encodeContentAux(ContentSet cs, string arg) { cs = MkAnyPropertyDeep() and result = "AnyMemberDeep" and arg = "" or cs = MkArrayElementDeep() and result = "ArrayElementDeep" and arg = "" + or + cs = MkOptionalStep(arg) and result = "OptionalStep" + or + cs = MkOptionalBarrier(arg) and result = "OptionalBarrier" } /** From 3b34cd72f2490f137316e25fc934b70a8dc83d0e Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 10 Sep 2024 15:01:51 +0200 Subject: [PATCH 08/25] JS: Handle split() with '#' or '?' separator in a separate summary This summary uses the notion of optional steps/barriers so it becomes configurable whether there is flow into the zero'th array element. Also makes sure we handle the second-argument version of split(). --- .../internal/flow_summaries/Strings.qll | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Strings.qll b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Strings.qll index 941b9a825c37..1135f6cb7f00 100644 --- a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Strings.qll +++ b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Strings.qll @@ -55,7 +55,9 @@ class StringSplit extends SummarizedCallable { StringSplit() { this = "String#split" } override DataFlow::MethodCallNode getACallSimple() { - result.getMethodName() = "split" and result.getNumArgument() = 1 + result.getMethodName() = "split" and + result.getNumArgument() = [1, 2] and + not result.getArgument(0).getStringValue() = ["#", "?"] } override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { @@ -64,3 +66,33 @@ class StringSplit extends SummarizedCallable { output = "ReturnValue.ArrayElement" } } + +/** + * A call of form `x.split("#")` or `x.split("?")`. + * + * These are of special significance when tracking a tainted URL suffix, such as `window.location.href`, + * because the first element of the resulting array should not be considered tainted. + * + * This summary defaults to the same behaviour as the general `.split()` case, but it contains optional steps + * and barriers named `tainted-url-suffix` that should be activated when tracking a tainted URL suffix. + */ +class StringSplitHashOrQuestionMark extends SummarizedCallable { + StringSplitHashOrQuestionMark() { this = "String#split with '#' or '?'" } + + override DataFlow::MethodCallNode getACallSimple() { + result.getMethodName() = "split" and + result.getNumArgument() = [1, 2] and + result.getArgument(0).getStringValue() = ["#", "?"] + } + + override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + preservesValue = false and + ( + input = "Argument[this].OptionalBarrier[tainted-url-suffix]" and + output = "ReturnValue.ArrayElement" + or + input = "Argument[this].OptionalStep[tainted-url-suffix]" and + output = "ReturnValue.ArrayElement[1]" // TODO: support ArrayElement[1..] + ) + } +} From 7790f68fe2ad3bc6b37a813f9f7fa85281fa0604 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 10 Sep 2024 15:02:29 +0200 Subject: [PATCH 09/25] JS: Make the TaintedUrlSuffix library use optional steps/barriers --- .../javascript/security/TaintedUrlSuffix.qll | 10 ++++++++++ .../security/dataflow/DomBasedXssQuery.qll | 2 ++ .../Security/CWE-079/DomBasedXss/Xss.expected | 14 ++++---------- .../DomBasedXss/XssWithAdditionalSources.expected | 13 ++++--------- .../Security/CWE-079/DomBasedXss/tst.js | 2 +- 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll b/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll index 683c5e19f4d4..39ea36a60c61 100644 --- a/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll +++ b/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll @@ -4,6 +4,7 @@ */ import javascript +private import semmle.javascript.dataflow.internal.DataFlowPrivate as DataFlowPrivate /** * Provides a flow label for reasoning about URLs with a tainted query and fragment part, @@ -45,6 +46,11 @@ module TaintedUrlSuffix { ] } + predicate isBarrier(Node node, FlowLabel label) { + label = label() and + DataFlowPrivate::optionalBarrier(node, "tainted-url-suffix") + } + /** * Holds if there is a flow step `src -> dst` involving the URL suffix taint label. * @@ -57,6 +63,10 @@ module TaintedUrlSuffix { TaintTracking::AdditionalTaintStep::step(src, dst) and not isSafeLocationProp(dst) or + srclbl = label() and + dstlbl.isTaint() and + DataFlowPrivate::optionalStep(src, "tainted-url-suffix", dst) + or // Transition from URL suffix to full taint when extracting the query/fragment part. srclbl = label() and dstlbl.isTaint() and diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssQuery.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssQuery.qll index 4da51cccb8c4..8a53e4f0790f 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssQuery.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssQuery.qll @@ -76,6 +76,8 @@ module DomBasedXssConfig implements DataFlow::StateConfigSig { isOptionallySanitizedNode(node) and lbl = [DataFlow::FlowLabel::taint(), prefixLabel(), TaintedUrlSuffix::label()] or + TaintedUrlSuffix::isBarrier(node, lbl) + or node = DataFlow::MakeLabeledBarrierGuard::getABarrierNode(lbl) } 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 d6dc0b1b44ee..28c31f305952 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 @@ -514,9 +514,6 @@ nodes | tst.js:371:7:371:39 | target | semmle.label | target | | tst.js:371:16:371:39 | documen ... .search | semmle.label | documen ... .search | | tst.js:374:18:374:23 | target | semmle.label | target | -| tst.js:377:18:377:39 | documen ... on.href | semmle.label | documen ... on.href | -| tst.js:377:18:377:50 | documen ... it("?") [ArrayElement] | semmle.label | documen ... it("?") [ArrayElement] | -| tst.js:377:18:377:53 | documen ... "?")[0] | semmle.label | documen ... "?")[0] | | tst.js:381:7:381:39 | target | semmle.label | target | | tst.js:381:7:381:39 | target [taint3] | semmle.label | target [taint3] | | tst.js:381:7:381:39 | target [taint8] | semmle.label | target [taint8] | @@ -549,7 +546,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:48 | window. ... it('#') [1] | semmle.label | window. ... it('#') [1] | | 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 | @@ -1115,8 +1112,6 @@ edges | tst.js:355:19:355:42 | documen ... .search | tst.js:355:10:355:42 | target | provenance | | | tst.js:371:7:371:39 | target | tst.js:374:18:374:23 | target | provenance | | | tst.js:371:16:371:39 | documen ... .search | tst.js:371:7:371:39 | target | provenance | | -| tst.js:377:18:377:39 | documen ... on.href | tst.js:377:18:377:50 | documen ... it("?") [ArrayElement] | provenance | | -| tst.js:377:18:377:50 | documen ... it("?") [ArrayElement] | tst.js:377:18:377:53 | documen ... "?")[0] | provenance | | | tst.js:381:7:381:39 | target | tst.js:384:18:384:23 | target | provenance | | | tst.js:381:7:381:39 | target | tst.js:386:18:386:23 | target | provenance | | | tst.js:381:7:381:39 | target | tst.js:397:18:397:23 | target | provenance | | @@ -1153,11 +1148,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:37 | window.location.hash | tst.js:424:18:424:48 | window. ... it('#') [1] | provenance | Config | | 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:424:18:424:48 | window. ... it('#') [1] | tst.js:424:18:424:51 | window. ... '#')[1] | provenance | | +| tst.js:424:18:424:48 | window. ... it('#') [1] | 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 | | @@ -1460,7 +1455,6 @@ subpaths | tst.js:360:21:360:26 | target | tst.js:355:19:355:42 | documen ... .search | tst.js:360:21:360:26 | target | Cross-site scripting vulnerability due to $@. | tst.js:355:19:355:42 | documen ... .search | user-provided value | | tst.js:363:18:363:23 | target | tst.js:355:19:355:42 | documen ... .search | tst.js:363:18:363:23 | target | Cross-site scripting vulnerability due to $@. | tst.js:355:19:355:42 | documen ... .search | user-provided value | | tst.js:374:18:374:23 | target | tst.js:371:16:371:39 | documen ... .search | tst.js:374:18:374:23 | target | Cross-site scripting vulnerability due to $@. | tst.js:371:16:371:39 | documen ... .search | user-provided value | -| tst.js:377:18:377:53 | documen ... "?")[0] | tst.js:377:18:377:39 | documen ... on.href | tst.js:377:18:377:53 | documen ... "?")[0] | Cross-site scripting vulnerability due to $@. | tst.js:377:18:377:39 | documen ... on.href | user-provided value | | tst.js:384:18:384:23 | target | tst.js:381:16:381:39 | documen ... .search | tst.js:384:18:384:23 | target | Cross-site scripting vulnerability due to $@. | tst.js:381:16:381:39 | documen ... .search | user-provided value | | tst.js:386:18:386:29 | target.taint | tst.js:381:16:381:39 | documen ... .search | tst.js:386:18:386:29 | target.taint | Cross-site scripting vulnerability due to $@. | tst.js:381:16:381:39 | documen ... .search | user-provided value | | tst.js:392:18:392:30 | target.taint3 | tst.js:391:19:391:42 | documen ... .search | tst.js:392:18:392:30 | target.taint3 | Cross-site scripting vulnerability due to $@. | tst.js:391:19:391:42 | documen ... .search | 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 0390a90f7e9e..d51182541288 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 @@ -519,9 +519,6 @@ nodes | tst.js:371:7:371:39 | target | semmle.label | target | | tst.js:371:16:371:39 | documen ... .search | semmle.label | documen ... .search | | tst.js:374:18:374:23 | target | semmle.label | target | -| tst.js:377:18:377:39 | documen ... on.href | semmle.label | documen ... on.href | -| tst.js:377:18:377:50 | documen ... it("?") [ArrayElement] | semmle.label | documen ... it("?") [ArrayElement] | -| tst.js:377:18:377:53 | documen ... "?")[0] | semmle.label | documen ... "?")[0] | | tst.js:381:7:381:39 | target | semmle.label | target | | tst.js:381:7:381:39 | target [taint3] | semmle.label | target [taint3] | | tst.js:381:7:381:39 | target [taint8] | semmle.label | target [taint8] | @@ -554,7 +551,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:48 | window. ... it('#') [1] | semmle.label | window. ... it('#') [1] | | 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 | @@ -1140,8 +1137,6 @@ edges | tst.js:355:19:355:42 | documen ... .search | tst.js:355:10:355:42 | target | provenance | | | tst.js:371:7:371:39 | target | tst.js:374:18:374:23 | target | provenance | | | tst.js:371:16:371:39 | documen ... .search | tst.js:371:7:371:39 | target | provenance | | -| tst.js:377:18:377:39 | documen ... on.href | tst.js:377:18:377:50 | documen ... it("?") [ArrayElement] | provenance | | -| tst.js:377:18:377:50 | documen ... it("?") [ArrayElement] | tst.js:377:18:377:53 | documen ... "?")[0] | provenance | | | tst.js:381:7:381:39 | target | tst.js:384:18:384:23 | target | provenance | | | tst.js:381:7:381:39 | target | tst.js:386:18:386:23 | target | provenance | | | tst.js:381:7:381:39 | target | tst.js:397:18:397:23 | target | provenance | | @@ -1178,11 +1173,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:37 | window.location.hash | tst.js:424:18:424:48 | window. ... it('#') [1] | provenance | Config | | 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:424:18:424:48 | window. ... it('#') [1] | tst.js:424:18:424:51 | window. ... '#')[1] | provenance | | +| tst.js:424:18:424:48 | window. ... it('#') [1] | 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 | | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tst.js b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tst.js index 1e42fa97fe24..3a8c59926451 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tst.js @@ -373,7 +373,7 @@ function test() { // NOT OK $('myId').html(target) - // OK [INCONSISTENCY] (TODO: fix) + // OK $('myid').html(document.location.href.split("?")[0]); } From e87e543850bb5614280bfcea0d258ed740bef60c Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 10 Sep 2024 15:02:51 +0200 Subject: [PATCH 10/25] JS: Ensure optional steps/barriers are computed in the correct stage --- .../dataflow/internal/FlowSummaryPrivate.qll | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll index e969ab39d37e..6ae42a90bd2b 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSummaryPrivate.qll @@ -126,7 +126,7 @@ string encodeArgumentPosition(ArgumentPosition pos) { } /** Gets the return kind corresponding to specification `"ReturnValue"`. */ -ReturnKind getStandardReturnValueKind() { result = MkNormalReturnKind() } +ReturnKind getStandardReturnValueKind() { result = MkNormalReturnKind() and Stage::ref() } private module FlowSummaryStepInput implements Private::StepsInputSig { DataFlowCall getACall(SummarizedCallable sc) { @@ -238,3 +238,12 @@ ContentSet decodeUnknownWithoutContent(AccessPathSyntax::AccessPathTokenBase tok */ bindingset[token] ContentSet decodeUnknownWithContent(AccessPathSyntax::AccessPathTokenBase token) { none() } + +cached +module Stage { + cached + predicate ref() { 1 = 1 } + + cached + predicate backref() { optionalStep(_, _, _) } +} From 133b016c7c659302d42e535dd2d08ddd0a61133b Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 10 Sep 2024 15:21:03 +0200 Subject: [PATCH 11/25] JS: Remove old 'split' handling from TaintedUrlSuffix --- .../ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll | 5 ----- 1 file changed, 5 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll b/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll index 39ea36a60c61..79dee94c58f1 100644 --- a/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll +++ b/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll @@ -80,11 +80,6 @@ module TaintedUrlSuffix { name = StringOps::substringMethodName() and not call.getArgument(0).getIntValue() = 0 or - // Split around '#' or '?' and extract the suffix - name = "split" and - call.getArgument(0).getStringValue() = ["#", "?"] and - not exists(call.getAPropertyRead("0")) // Avoid false flow to the prefix - or // Replace '#' and '?' with nothing name = "replace" and call.getArgument(0).getStringValue() = ["#", "?"] and From da696817a326c34f295e24662475da92c5f077bd Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 10 Sep 2024 15:21:24 +0200 Subject: [PATCH 12/25] JS: Convert 'split' taint step to legacy taint step --- .../semmle/javascript/dataflow/TaintTracking.qll | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll index e6eccf6097d4..13970c161436 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll @@ -356,6 +356,16 @@ module TaintTracking { } } + private class LegacySplitTaintStep extends LegacyTaintStep { + override predicate stringManipulationStep(DataFlow::Node pred, DataFlow::Node target) { + exists(DataFlow::MethodCallNode call | + call.getMethodName() = "split" and + pred = call.getReceiver() and + target = call + ) + } + } + /** * A taint propagating data flow edge arising from string manipulation * functions defined in the standard library. @@ -372,9 +382,8 @@ module TaintTracking { [ "anchor", "big", "blink", "bold", "concat", "fixed", "fontcolor", "fontsize", "italics", "link", "padEnd", "padStart", "repeat", "replace", "replaceAll", "slice", - "small", "split", "strike", "sub", "substr", "substring", "sup", - "toLocaleLowerCase", "toLocaleUpperCase", "toLowerCase", "toUpperCase", "trim", - "trimLeft", "trimRight" + "small", "strike", "sub", "substr", "substring", "sup", "toLocaleLowerCase", + "toLocaleUpperCase", "toLowerCase", "toUpperCase", "trim", "trimLeft", "trimRight" ] or // sorted, interesting, properties of Object.prototype From 15fc450a9edeca2487efc7e35560e82ced894086 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 10 Sep 2024 15:22:11 +0200 Subject: [PATCH 13/25] JS: Add reminder to update ClientSideUrlRedirect --- .../security/dataflow/ClientSideUrlRedirectCustomizations.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll index e79acdbf396e..65d9b01fe884 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll @@ -35,7 +35,7 @@ module ClientSideUrlRedirect { * hence are only partially user-controlled. */ abstract class DocumentUrl extends DataFlow::FlowLabel { - DocumentUrl() { this = "document.url" } + DocumentUrl() { this = "document.url" } // TODO: replace with TaintedUrlSuffix } /** A source of remote user input, considered as a flow source for unvalidated URL redirects. */ From e4f7560bcdfa65353354c6d5aa3692225330d6b5 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 10 Sep 2024 15:32:53 +0200 Subject: [PATCH 14/25] JS: Add missing qldoc --- .../ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll b/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll index 79dee94c58f1..8f9e13354c38 100644 --- a/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll +++ b/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll @@ -46,6 +46,12 @@ module TaintedUrlSuffix { ] } + /** + * Holds if `node` should be a barrier for the given `label`. + * + * This should be used in the `isBarrier` predicate of a configuration that uses the tainted-url-suffix + * label. + */ predicate isBarrier(Node node, FlowLabel label) { label = label() and DataFlowPrivate::optionalBarrier(node, "tainted-url-suffix") From 3fcf4ef7a19c13836660877f004c3f4d1ae677aa Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 11 Sep 2024 10:48:59 +0200 Subject: [PATCH 15/25] JS: More precise model of .shift() Array.prototype.shift only returns the first array element. The mutation of Argument[this] is not yet modelled, and is better handled when we have use-use flow. --- .../ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 0723cbf3767f..614d67ae0773 100644 --- a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll +++ b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll @@ -484,7 +484,7 @@ class Shift extends SummarizedCallable { override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { preservesValue = true and - input = "Argument[this].ArrayElement" and + input = "Argument[this].ArrayElement[0]" and output = "ReturnValue" } } From 3ea1134cc15a95439427ef015f2ee4098f3f0dca Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 11 Sep 2024 11:04:41 +0200 Subject: [PATCH 16/25] JS: Add inline test for .shift() method --- .../ql/test/library-tests/TripleDot/arrays.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 javascript/ql/test/library-tests/TripleDot/arrays.js diff --git a/javascript/ql/test/library-tests/TripleDot/arrays.js b/javascript/ql/test/library-tests/TripleDot/arrays.js new file mode 100644 index 000000000000..d6171c56c26f --- /dev/null +++ b/javascript/ql/test/library-tests/TripleDot/arrays.js @@ -0,0 +1,15 @@ +import 'dummy'; + +function shiftKnown() { + let array = [source('shift.1'), source('shift.2')]; + sink(array.shift()); // $ hasValueFlow=shift.1 + sink(array.shift()); // $ SPURIOUS: hasValueFlow=shift.1 MISSING: hasValueFlow=shift.2 +} + +function shiftUnknown() { + const array = new Array(Math.floor(Math.random() * 10)); + array.push(source('shift.unkn')); + sink(array.shift()); // $ hasValueFlow=shift.unkn + sink(array.shift()); // $ hasValueFlow=shift.unkn + sink(array.shift()); // $ hasValueFlow=shift.unkn +} From 3b09bc548e60be45342caecb744b0dfe7c48572a Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 11 Sep 2024 13:23:10 +0200 Subject: [PATCH 17/25] JS: Add taint step for shift() --- .../semmle/javascript/internal/flow_summaries/Arrays.qll | 5 +++++ javascript/ql/test/library-tests/TripleDot/arrays.js | 7 +++++++ 2 files changed, 12 insertions(+) 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 614d67ae0773..e242ed35a67d 100644 --- a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll +++ b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll @@ -486,6 +486,11 @@ class Shift extends SummarizedCallable { preservesValue = true and input = "Argument[this].ArrayElement[0]" and output = "ReturnValue" + or + // ArrayElement[0] is not automatically converted to a taint step, so add it manually + preservesValue = false and + input = "Argument[this]" and + output = "ReturnValue" } } diff --git a/javascript/ql/test/library-tests/TripleDot/arrays.js b/javascript/ql/test/library-tests/TripleDot/arrays.js index d6171c56c26f..0a18066eb767 100644 --- a/javascript/ql/test/library-tests/TripleDot/arrays.js +++ b/javascript/ql/test/library-tests/TripleDot/arrays.js @@ -13,3 +13,10 @@ function shiftUnknown() { sink(array.shift()); // $ hasValueFlow=shift.unkn sink(array.shift()); // $ hasValueFlow=shift.unkn } + +function shiftTaint() { + const array = source('shift.directly-tainted'); + sink(array.shift()); // $ hasTaintFlow=shift.directly-tainted + sink(array.shift()); // $ hasTaintFlow=shift.directly-tainted + sink(array.shift()); // $ hasTaintFlow=shift.directly-tainted +} From cf90c83604db7944caa546473a7d028a288b7329 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 11 Sep 2024 13:27:12 +0200 Subject: [PATCH 18/25] JS: Accept changes to nodes/edges results --- .../IndirectCommandInjection.expected | 31 +++++++++++++++++++ .../Security/CWE-079/DomBasedXss/Xss.expected | 6 ---- .../XssWithAdditionalSources.expected | 6 ---- .../ClientSideUrlRedirect.expected | 9 ++++++ .../PrototypePollutingAssignment.expected | 9 ++++++ 5 files changed, 49 insertions(+), 12 deletions(-) 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 a6b90c01ff1f..60a29847a102 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 @@ -7,33 +7,52 @@ edges | command-line-parameter-command-injection.js:10:6:10:33 | args | command-line-parameter-command-injection.js:11:14:11:17 | args | provenance | | | command-line-parameter-command-injection.js:10:6:10:33 | args | command-line-parameter-command-injection.js:12:26:12:29 | args | provenance | | | command-line-parameter-command-injection.js:10:6:10:33 | args | command-line-parameter-command-injection.js:14:18:14:21 | args | provenance | | +| command-line-parameter-command-injection.js:10:6:10:33 | args [ArrayElement] | command-line-parameter-command-injection.js:11:14:11:17 | args [ArrayElement] | provenance | | +| command-line-parameter-command-injection.js:10:6:10:33 | args [ArrayElement] | command-line-parameter-command-injection.js:12:26:12:29 | args [ArrayElement] | provenance | | | command-line-parameter-command-injection.js:10:6:10:33 | args [ArrayElement] | command-line-parameter-command-injection.js:14:18:14:21 | args [ArrayElement] | provenance | | | command-line-parameter-command-injection.js:10:13:10:24 | process.argv | command-line-parameter-command-injection.js:10:13:10:33 | process ... lice(2) | provenance | | | command-line-parameter-command-injection.js:10:13:10:24 | process.argv | command-line-parameter-command-injection.js:10:13:10:33 | process ... lice(2) [ArrayElement] | provenance | | | command-line-parameter-command-injection.js:10:13:10:33 | process ... lice(2) | command-line-parameter-command-injection.js:10:6:10:33 | args | provenance | | | command-line-parameter-command-injection.js:10:13:10:33 | process ... lice(2) [ArrayElement] | command-line-parameter-command-injection.js:10:6:10:33 | args [ArrayElement] | provenance | | | command-line-parameter-command-injection.js:11:14:11:17 | args | command-line-parameter-command-injection.js:11:14:11:20 | args[0] | provenance | | +| command-line-parameter-command-injection.js:11:14:11:17 | args [ArrayElement] | command-line-parameter-command-injection.js:11:14:11:20 | args[0] | provenance | | | command-line-parameter-command-injection.js:12:26:12:29 | args | command-line-parameter-command-injection.js:12:14:12:32 | "cmd.sh " + args[0] | provenance | | +| command-line-parameter-command-injection.js:12:26:12:29 | args [ArrayElement] | command-line-parameter-command-injection.js:12:26:12:32 | args[0] | provenance | | +| command-line-parameter-command-injection.js:12:26:12:32 | args[0] | command-line-parameter-command-injection.js:12:14:12:32 | "cmd.sh " + args[0] | provenance | | | command-line-parameter-command-injection.js:14:6:14:30 | fewerArgs | command-line-parameter-command-injection.js:15:14:15:22 | fewerArgs | provenance | | | command-line-parameter-command-injection.js:14:6:14:30 | fewerArgs | command-line-parameter-command-injection.js:16:26:16:34 | fewerArgs | provenance | | | command-line-parameter-command-injection.js:14:6:14:30 | fewerArgs | command-line-parameter-command-injection.js:18:13:18:21 | fewerArgs | provenance | | +| command-line-parameter-command-injection.js:14:6:14:30 | fewerArgs [ArrayElement] | command-line-parameter-command-injection.js:15:14:15:22 | fewerArgs [ArrayElement] | provenance | | +| command-line-parameter-command-injection.js:14:6:14:30 | fewerArgs [ArrayElement] | command-line-parameter-command-injection.js:16:26:16:34 | fewerArgs [ArrayElement] | provenance | | +| command-line-parameter-command-injection.js:14:6:14:30 | fewerArgs [ArrayElement] | command-line-parameter-command-injection.js:18:13:18:21 | fewerArgs [ArrayElement] | provenance | | | command-line-parameter-command-injection.js:14:18:14:21 | args | command-line-parameter-command-injection.js:14:18:14:30 | args.slice(1) | provenance | | +| command-line-parameter-command-injection.js:14:18:14:21 | args | command-line-parameter-command-injection.js:14:18:14:30 | args.slice(1) [ArrayElement] | provenance | | | command-line-parameter-command-injection.js:14:18:14:21 | args [ArrayElement] | command-line-parameter-command-injection.js:14:18:14:30 | args.slice(1) | provenance | | +| command-line-parameter-command-injection.js:14:18:14:21 | args [ArrayElement] | command-line-parameter-command-injection.js:14:18:14:30 | args.slice(1) [ArrayElement] | provenance | | | command-line-parameter-command-injection.js:14:18:14:30 | args.slice(1) | command-line-parameter-command-injection.js:14:6:14:30 | fewerArgs | provenance | | +| command-line-parameter-command-injection.js:14:18:14:30 | args.slice(1) [ArrayElement] | command-line-parameter-command-injection.js:14:6:14:30 | fewerArgs [ArrayElement] | provenance | | | command-line-parameter-command-injection.js:15:14:15:22 | fewerArgs | command-line-parameter-command-injection.js:15:14:15:25 | fewerArgs[0] | provenance | | +| command-line-parameter-command-injection.js:15:14:15:22 | fewerArgs [ArrayElement] | command-line-parameter-command-injection.js:15:14:15:25 | fewerArgs[0] | provenance | | | command-line-parameter-command-injection.js:16:26:16:34 | fewerArgs | command-line-parameter-command-injection.js:16:14:16:37 | "cmd.sh ... Args[0] | provenance | | +| command-line-parameter-command-injection.js:16:26:16:34 | fewerArgs [ArrayElement] | command-line-parameter-command-injection.js:16:26:16:37 | fewerArgs[0] | provenance | | +| command-line-parameter-command-injection.js:16:26:16:37 | fewerArgs[0] | command-line-parameter-command-injection.js:16:14:16:37 | "cmd.sh ... Args[0] | provenance | | | command-line-parameter-command-injection.js:18:6:18:24 | arg0 | command-line-parameter-command-injection.js:19:14:19:17 | arg0 | provenance | | | command-line-parameter-command-injection.js:18:6:18:24 | arg0 | command-line-parameter-command-injection.js:20:26:20:29 | arg0 | provenance | | | command-line-parameter-command-injection.js:18:13:18:21 | fewerArgs | command-line-parameter-command-injection.js:18:6:18:24 | arg0 | provenance | | +| command-line-parameter-command-injection.js:18:13:18:21 | fewerArgs [ArrayElement] | command-line-parameter-command-injection.js:18:13:18:24 | fewerArgs[0] | provenance | | +| command-line-parameter-command-injection.js:18:13:18:24 | fewerArgs[0] | command-line-parameter-command-injection.js:18:6:18:24 | arg0 | provenance | | | 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:26:32:26:35 | args [ArrayElement] | 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:26:32:26:35 | args [ArrayElement] | command-line-parameter-command-injection.js:26:32:26:38 | args[0] | provenance | | +| command-line-parameter-command-injection.js:26:32:26:38 | args[0] | 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 | | @@ -139,19 +158,29 @@ nodes | command-line-parameter-command-injection.js:10:13:10:33 | process ... lice(2) | semmle.label | process ... lice(2) | | command-line-parameter-command-injection.js:10:13:10:33 | process ... lice(2) [ArrayElement] | semmle.label | process ... lice(2) [ArrayElement] | | command-line-parameter-command-injection.js:11:14:11:17 | args | semmle.label | args | +| command-line-parameter-command-injection.js:11:14:11:17 | args [ArrayElement] | semmle.label | args [ArrayElement] | | command-line-parameter-command-injection.js:11:14:11:20 | args[0] | semmle.label | args[0] | | command-line-parameter-command-injection.js:12:14:12:32 | "cmd.sh " + args[0] | semmle.label | "cmd.sh " + args[0] | | command-line-parameter-command-injection.js:12:26:12:29 | args | semmle.label | args | +| command-line-parameter-command-injection.js:12:26:12:29 | args [ArrayElement] | semmle.label | args [ArrayElement] | +| command-line-parameter-command-injection.js:12:26:12:32 | args[0] | semmle.label | args[0] | | command-line-parameter-command-injection.js:14:6:14:30 | fewerArgs | semmle.label | fewerArgs | +| command-line-parameter-command-injection.js:14:6:14:30 | fewerArgs [ArrayElement] | semmle.label | fewerArgs [ArrayElement] | | command-line-parameter-command-injection.js:14:18:14:21 | args | semmle.label | args | | command-line-parameter-command-injection.js:14:18:14:21 | args [ArrayElement] | semmle.label | args [ArrayElement] | | command-line-parameter-command-injection.js:14:18:14:30 | args.slice(1) | semmle.label | args.slice(1) | +| command-line-parameter-command-injection.js:14:18:14:30 | args.slice(1) [ArrayElement] | semmle.label | args.slice(1) [ArrayElement] | | command-line-parameter-command-injection.js:15:14:15:22 | fewerArgs | semmle.label | fewerArgs | +| command-line-parameter-command-injection.js:15:14:15:22 | fewerArgs [ArrayElement] | semmle.label | fewerArgs [ArrayElement] | | command-line-parameter-command-injection.js:15:14:15:25 | fewerArgs[0] | semmle.label | fewerArgs[0] | | command-line-parameter-command-injection.js:16:14:16:37 | "cmd.sh ... Args[0] | semmle.label | "cmd.sh ... Args[0] | | command-line-parameter-command-injection.js:16:26:16:34 | fewerArgs | semmle.label | fewerArgs | +| command-line-parameter-command-injection.js:16:26:16:34 | fewerArgs [ArrayElement] | semmle.label | fewerArgs [ArrayElement] | +| command-line-parameter-command-injection.js:16:26:16:37 | fewerArgs[0] | semmle.label | fewerArgs[0] | | command-line-parameter-command-injection.js:18:6:18:24 | arg0 | semmle.label | arg0 | | command-line-parameter-command-injection.js:18:13:18:21 | fewerArgs | semmle.label | fewerArgs | +| command-line-parameter-command-injection.js:18:13:18:21 | fewerArgs [ArrayElement] | semmle.label | fewerArgs [ArrayElement] | +| command-line-parameter-command-injection.js:18:13:18:24 | fewerArgs[0] | semmle.label | fewerArgs[0] | | command-line-parameter-command-injection.js:19:14:19:17 | arg0 | semmle.label | arg0 | | 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 | @@ -162,6 +191,8 @@ nodes | 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:26:32:26:35 | args [ArrayElement] | semmle.label | args [ArrayElement] | +| command-line-parameter-command-injection.js:26:32:26:38 | args[0] | semmle.label | args[0] | | 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] | 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 28c31f305952..1e35f0d6edb8 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 @@ -545,7 +545,6 @@ nodes | tst.js:421:20:421:24 | match | semmle.label | match | | 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('#') [1] | semmle.label | window. ... it('#') [1] | | tst.js:424:18:424:51 | window. ... '#')[1] | semmle.label | window. ... '#')[1] | | tst.js:428:7:428:39 | target | semmle.label | target | @@ -1146,13 +1145,8 @@ edges | tst.js:419:15:419:55 | window. ... (\\w+)/) | tst.js:419:7:419:55 | match | provenance | | | tst.js:421:20:421:24 | match | tst.js:421:20:421:27 | match[1] | provenance | | | 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('#') [1] | provenance | Config | -| 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('#') [1] | tst.js:424:18:424:51 | window. ... '#')[1] | provenance | | -| tst.js:424:18:424:48 | window. ... it('#') [1] | 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 | | 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 d51182541288..42841b5ffd73 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 @@ -550,7 +550,6 @@ nodes | tst.js:421:20:421:24 | match | semmle.label | match | | 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('#') [1] | semmle.label | window. ... it('#') [1] | | tst.js:424:18:424:51 | window. ... '#')[1] | semmle.label | window. ... '#')[1] | | tst.js:428:7:428:39 | target | semmle.label | target | @@ -1171,13 +1170,8 @@ edges | tst.js:419:15:419:55 | window. ... (\\w+)/) | tst.js:419:7:419:55 | match | provenance | | | tst.js:421:20:421:24 | match | tst.js:421:20:421:27 | match[1] | provenance | | | 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('#') [1] | provenance | Config | -| 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('#') [1] | tst.js:424:18:424:51 | window. ... '#')[1] | provenance | | -| tst.js:424:18:424:48 | window. ... it('#') [1] | 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 | | diff --git a/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected index c245c3e3a107..e1194cd81542 100644 --- a/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected +++ b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected @@ -42,10 +42,14 @@ nodes | tst10.js:14:17:14:56 | 'https: ... .search | semmle.label | 'https: ... .search | | tst10.js:14:33:14:56 | documen ... .search | semmle.label | documen ... .search | | tst12.js:3:9:3:50 | urlParts | semmle.label | urlParts | +| tst12.js:3:9:3:50 | urlParts [ArrayElement] | semmle.label | urlParts [ArrayElement] | | tst12.js:3:20:3:39 | window.location.hash | semmle.label | window.location.hash | | tst12.js:3:20:3:50 | window. ... it('?') | semmle.label | window. ... it('?') | +| tst12.js:3:20:3:50 | window. ... it('?') [ArrayElement] | semmle.label | window. ... it('?') [ArrayElement] | | tst12.js:4:9:4:45 | loc | semmle.label | loc | | tst12.js:4:15:4:22 | urlParts | semmle.label | urlParts | +| tst12.js:4:15:4:22 | urlParts [ArrayElement] | semmle.label | urlParts [ArrayElement] | +| tst12.js:4:15:4:25 | urlParts[0] | semmle.label | urlParts[0] | | tst12.js:5:23:5:25 | loc | semmle.label | loc | | tst13.js:2:9:2:52 | payload | semmle.label | payload | | tst13.js:2:19:2:42 | documen ... .search | semmle.label | documen ... .search | @@ -146,10 +150,15 @@ edges | tst10.js:11:27:11:50 | documen ... .search | tst10.js:11:17:11:50 | '//foo' ... .search | provenance | | | tst10.js:14:33:14:56 | documen ... .search | tst10.js:14:17:14:56 | 'https: ... .search | provenance | | | tst12.js:3:9:3:50 | urlParts | tst12.js:4:15:4:22 | urlParts | provenance | | +| tst12.js:3:9:3:50 | urlParts [ArrayElement] | tst12.js:4:15:4:22 | urlParts [ArrayElement] | provenance | | | tst12.js:3:20:3:39 | window.location.hash | tst12.js:3:20:3:50 | window. ... it('?') | provenance | | +| tst12.js:3:20:3:39 | window.location.hash | tst12.js:3:20:3:50 | window. ... it('?') [ArrayElement] | provenance | | | tst12.js:3:20:3:50 | window. ... it('?') | tst12.js:3:9:3:50 | urlParts | provenance | | +| tst12.js:3:20:3:50 | window. ... it('?') [ArrayElement] | tst12.js:3:9:3:50 | urlParts [ArrayElement] | provenance | | | tst12.js:4:9:4:45 | loc | tst12.js:5:23:5:25 | loc | provenance | | | tst12.js:4:15:4:22 | urlParts | tst12.js:4:9:4:45 | loc | provenance | | +| tst12.js:4:15:4:22 | urlParts [ArrayElement] | tst12.js:4:15:4:25 | urlParts[0] | provenance | | +| tst12.js:4:15:4:25 | urlParts[0] | tst12.js:4:9:4:45 | loc | provenance | | | tst13.js:2:9:2:52 | payload | tst13.js:4:15:4:21 | payload | provenance | | | tst13.js:2:9:2:52 | payload | tst13.js:8:21:8:27 | payload | provenance | | | tst13.js:2:9:2:52 | payload | tst13.js:12:14:12:20 | payload | provenance | | diff --git a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/PrototypePollutingAssignment.expected b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/PrototypePollutingAssignment.expected index 46afcf5a14f8..46e9be97d631 100644 --- a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/PrototypePollutingAssignment.expected +++ b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/PrototypePollutingAssignment.expected @@ -18,11 +18,16 @@ edges | lib.js:26:14:26:17 | path | lib.js:26:14:26:20 | path[0] | provenance | Config | | lib.js:26:14:26:20 | path[0] | lib.js:26:10:26:21 | obj[path[0]] | provenance | Config | | lib.js:30:9:30:52 | args | lib.js:32:14:32:17 | args | provenance | | +| lib.js:30:9:30:52 | args [ArrayElement] | lib.js:32:14:32:17 | args [ArrayElement] | provenance | | | lib.js:30:16:30:52 | Array.p ... uments) | lib.js:30:9:30:52 | args | provenance | | +| lib.js:30:16:30:52 | Array.p ... uments) [ArrayElement] | lib.js:30:9:30:52 | args [ArrayElement] | provenance | | | lib.js:30:16:30:52 | reflective call | lib.js:30:16:30:52 | Array.p ... uments) | provenance | | +| lib.js:30:16:30:52 | reflective call [ArrayElement] | lib.js:30:16:30:52 | Array.p ... uments) [ArrayElement] | provenance | | | lib.js:30:43:30:51 | arguments | lib.js:30:16:30:52 | reflective call | provenance | Config | +| lib.js:30:43:30:51 | arguments | lib.js:30:16:30:52 | reflective call [ArrayElement] | provenance | Config | | lib.js:32:7:32:20 | path | lib.js:34:7:34:10 | path | provenance | | | lib.js:32:14:32:17 | args | lib.js:32:14:32:20 | args[1] | provenance | Config | +| lib.js:32:14:32:17 | args [ArrayElement] | lib.js:32:14:32:20 | args[1] | provenance | | | lib.js:32:14:32:20 | args[1] | lib.js:32:7:32:20 | path | provenance | | | lib.js:34:7:34:10 | path | lib.js:34:7:34:13 | path[0] | provenance | Config | | lib.js:34:7:34:13 | path[0] | lib.js:34:3:34:14 | obj[path[0]] | provenance | Config | @@ -125,11 +130,15 @@ nodes | lib.js:26:14:26:17 | path | semmle.label | path | | lib.js:26:14:26:20 | path[0] | semmle.label | path[0] | | lib.js:30:9:30:52 | args | semmle.label | args | +| lib.js:30:9:30:52 | args [ArrayElement] | semmle.label | args [ArrayElement] | | lib.js:30:16:30:52 | Array.p ... uments) | semmle.label | Array.p ... uments) | +| lib.js:30:16:30:52 | Array.p ... uments) [ArrayElement] | semmle.label | Array.p ... uments) [ArrayElement] | | lib.js:30:16:30:52 | reflective call | semmle.label | reflective call | +| lib.js:30:16:30:52 | reflective call [ArrayElement] | semmle.label | reflective call [ArrayElement] | | lib.js:30:43:30:51 | arguments | semmle.label | arguments | | lib.js:32:7:32:20 | path | semmle.label | path | | lib.js:32:14:32:17 | args | semmle.label | args | +| lib.js:32:14:32:17 | args [ArrayElement] | semmle.label | args [ArrayElement] | | lib.js:32:14:32:20 | args[1] | semmle.label | args[1] | | lib.js:34:3:34:14 | obj[path[0]] | semmle.label | obj[path[0]] | | lib.js:34:7:34:10 | path | semmle.label | path | From e1bed42481b2b48f82d35742939d32daffc589ea Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 11 Sep 2024 15:02:36 +0200 Subject: [PATCH 19/25] JS: Add inline expectation test specifically for TaintedUrlSuffix --- .../TaintedUrlSuffix/test.expected | 2 + .../library-tests/TaintedUrlSuffix/test.ql | 52 +++++++++++++++++++ .../library-tests/TaintedUrlSuffix/tst.js | 22 ++++++++ 3 files changed, 76 insertions(+) create mode 100644 javascript/ql/test/library-tests/TaintedUrlSuffix/test.expected create mode 100644 javascript/ql/test/library-tests/TaintedUrlSuffix/test.ql create mode 100644 javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js diff --git a/javascript/ql/test/library-tests/TaintedUrlSuffix/test.expected b/javascript/ql/test/library-tests/TaintedUrlSuffix/test.expected new file mode 100644 index 000000000000..8ec8033d086e --- /dev/null +++ b/javascript/ql/test/library-tests/TaintedUrlSuffix/test.expected @@ -0,0 +1,2 @@ +testFailures +failures diff --git a/javascript/ql/test/library-tests/TaintedUrlSuffix/test.ql b/javascript/ql/test/library-tests/TaintedUrlSuffix/test.ql new file mode 100644 index 000000000000..f3d43dd41047 --- /dev/null +++ b/javascript/ql/test/library-tests/TaintedUrlSuffix/test.ql @@ -0,0 +1,52 @@ +import javascript +import testUtilities.InlineExpectationsTest +import semmle.javascript.security.TaintedUrlSuffix + +module TestConfig implements DataFlow::StateConfigSig { + class FlowState = DataFlow::FlowLabel; + + predicate isSource(DataFlow::Node node, DataFlow::FlowLabel state) { + node = TaintedUrlSuffix::source() and state = TaintedUrlSuffix::label() + or + node instanceof RemoteFlowSource and + not node = TaintedUrlSuffix::source() and + state.isTaint() + } + + predicate isSink(DataFlow::Node node, DataFlow::FlowLabel state) { none() } + + predicate isSink(DataFlow::Node node) { + exists(DataFlow::CallNode call | + call.getCalleeName() = "sink" and + node = call.getArgument(0) + ) + } + + predicate isAdditionalFlowStep( + DataFlow::Node node1, DataFlow::FlowLabel state1, DataFlow::Node node2, + DataFlow::FlowLabel state2 + ) { + TaintedUrlSuffix::step(node1, node2, state1, state2) + } + + predicate isBarrier(DataFlow::Node node, DataFlow::FlowLabel label) { + TaintedUrlSuffix::isBarrier(node, label) + } +} + +module TestFlow = TaintTracking::GlobalWithState; + +module InlineTest implements TestSig { + string getARelevantTag() { result = "flow" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "flow" and + exists(TestFlow::PathNode src, TestFlow::PathNode sink | TestFlow::flowPath(src, sink) | + sink.getLocation() = location and + element = "" and + value = sink.getState() + ) + } +} + +import MakeTest diff --git a/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js b/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js new file mode 100644 index 000000000000..3fdfd9693064 --- /dev/null +++ b/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js @@ -0,0 +1,22 @@ +import 'dummy'; + +function t1() { + const href = window.location.href; + + sink(href); // $ flow=tainted-url-suffix + + sink(href.split('#')[0]); // $ MISSING: flow=tainted-url-suffix SPURIOUS: flow=taint + sink(href.split('#')[1]); // $ flow=taint + sink(href.split('#').pop()); // $ flow=taint + sink(href.split('#')[2]); // $ flow=taint + + sink(href.split('?')[0]); // $ MISSING: flow=tainted-url-suffix + sink(href.split('?')[1]); // $ flow=taint + sink(href.split('?').pop()); // $ flow=taint + sink(href.split('?')[2]); // $ flow=taint + + sink(href.split(blah())[0]); // $ flow=tainted-url-suffix + sink(href.split(blah())[1]); // $ flow=tainted-url-suffix + sink(href.split(blah()).pop()); // $ flow=tainted-url-suffix + sink(href.split(blah())[2]); // $ flow=tainted-url-suffix +} From bc04131c72d3a88394f0136219c1b82d5bf1c057 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 11 Sep 2024 15:06:48 +0200 Subject: [PATCH 20/25] JS: Disallow implicit reads before an optional step --- .../javascript/dataflow/internal/TaintTrackingPrivate.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll index 69d275a74dce..a16da33664d6 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/TaintTrackingPrivate.qll @@ -61,5 +61,7 @@ predicate defaultTaintSanitizer(DataFlow::Node node) { bindingset[node] predicate defaultImplicitTaintRead(DataFlow::Node node, ContentSet c) { exists(node) and - c = [ContentSet::promiseValue(), ContentSet::arrayElement()] + c = [ContentSet::promiseValue(), ContentSet::arrayElement()] and + // Optional steps are added through isAdditionalFlowStep but we don't want the implicit reads + not optionalStep(node, _, _) } From 2712bf821addd46e49aa249559a5f80be85e1663 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 11 Sep 2024 15:09:03 +0200 Subject: [PATCH 21/25] JS: Fix a bug in isSafeClientSideUrlProperty --- javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll | 2 +- javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll index 13970c161436..ad42131ca4df 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll @@ -255,7 +255,7 @@ module TaintTracking { exists(StringSplitCall c | c.getBaseString().getALocalSource() = [DOM::locationRef(), DOM::locationRef().getAPropertyRead("href")] and - c.getSeparator() = "?" and + c.getSeparator() = ["?", "#"] and read = c.getAPropertyRead("0") ) } diff --git a/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js b/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js index 3fdfd9693064..243b0374697e 100644 --- a/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js +++ b/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js @@ -5,7 +5,7 @@ function t1() { sink(href); // $ flow=tainted-url-suffix - sink(href.split('#')[0]); // $ MISSING: flow=tainted-url-suffix SPURIOUS: flow=taint + sink(href.split('#')[0]); // $ MISSING: flow=tainted-url-suffix sink(href.split('#')[1]); // $ flow=taint sink(href.split('#').pop()); // $ flow=taint sink(href.split('#')[2]); // $ flow=taint From 74ab346348e4257d12a9bc3bb66ed4854f4b6a64 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 11 Sep 2024 15:38:39 +0200 Subject: [PATCH 22/25] JS: Do not include taint steps in TaintedUrlSuffix::step TaintedUrlSuffix is currently only used in TaintTracking configs meaning it is already propagated by taint steps. The inclusion of these taint steps here however meant that implicit reads could appear prior to any of these steps. This was is problematic for PropRead steps as an expression like x[0] could spuriously read from array element 1 via the path: x [element 1] x [empty access path] (after implicit read) x[0] (taint step through PropRead) --- .../javascript/security/TaintedUrlSuffix.qll | 16 ---------------- .../test/library-tests/TaintedUrlSuffix/tst.js | 4 ++-- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll b/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll index 8f9e13354c38..231e6e4dc9b8 100644 --- a/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll +++ b/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll @@ -36,16 +36,6 @@ module TaintedUrlSuffix { result.getKind().isUrl() } - /** Holds for `pred -> succ` is a step of form `x -> x.p` */ - private predicate isSafeLocationProp(DataFlow::PropRead read) { - // Ignore properties that refer to the scheme, domain, port, auth, or path. - read.getPropertyName() = - [ - "protocol", "scheme", "host", "hostname", "domain", "origin", "port", "path", "pathname", - "username", "password", "auth" - ] - } - /** * Holds if `node` should be a barrier for the given `label`. * @@ -63,12 +53,6 @@ module TaintedUrlSuffix { * This handles steps through string operations, promises, URL parsers, and URL accessors. */ predicate step(Node src, Node dst, FlowLabel srclbl, FlowLabel dstlbl) { - // Inherit all ordinary taint steps except `x -> x.p` steps - srclbl = label() and - dstlbl = label() and - TaintTracking::AdditionalTaintStep::step(src, dst) and - not isSafeLocationProp(dst) - or srclbl = label() and dstlbl.isTaint() and DataFlowPrivate::optionalStep(src, "tainted-url-suffix", dst) diff --git a/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js b/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js index 243b0374697e..80d80597e8af 100644 --- a/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js +++ b/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js @@ -8,12 +8,12 @@ function t1() { sink(href.split('#')[0]); // $ MISSING: flow=tainted-url-suffix sink(href.split('#')[1]); // $ flow=taint sink(href.split('#').pop()); // $ flow=taint - sink(href.split('#')[2]); // $ flow=taint + sink(href.split('#')[2]); // $ MISSING: flow=taint // currently the split() summary only propagates to index 1 sink(href.split('?')[0]); // $ MISSING: flow=tainted-url-suffix sink(href.split('?')[1]); // $ flow=taint sink(href.split('?').pop()); // $ flow=taint - sink(href.split('?')[2]); // $ flow=taint + sink(href.split('?')[2]); // $ MISSING: flow=taint sink(href.split(blah())[0]); // $ flow=tainted-url-suffix sink(href.split(blah())[1]); // $ flow=tainted-url-suffix From 0e4e0f4fdd42d2ab85ef52f820845589d0b46264 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 11 Sep 2024 15:47:35 +0200 Subject: [PATCH 23/25] JS: Preverse tainted-url-suffix when stepping into prefix A URL of form https://example.com?evil#bar will contain '?evil' after splitting out the '#' suffix, and vice versa. --- .../semmle/javascript/internal/flow_summaries/Strings.qll | 7 +++++-- .../lib/semmle/javascript/security/TaintedUrlSuffix.qll | 8 ++++++-- javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js | 8 ++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Strings.qll b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Strings.qll index 1135f6cb7f00..9267ab598fb8 100644 --- a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Strings.qll +++ b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Strings.qll @@ -88,10 +88,13 @@ class StringSplitHashOrQuestionMark extends SummarizedCallable { override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { preservesValue = false and ( - input = "Argument[this].OptionalBarrier[tainted-url-suffix]" and + input = "Argument[this].OptionalBarrier[split-url-suffix]" and output = "ReturnValue.ArrayElement" or - input = "Argument[this].OptionalStep[tainted-url-suffix]" and + input = "Argument[this].OptionalStep[split-url-suffix-pre]" and + output = "ReturnValue.ArrayElement[0]" + or + input = "Argument[this].OptionalStep[split-url-suffix-post]" and output = "ReturnValue.ArrayElement[1]" // TODO: support ArrayElement[1..] ) } diff --git a/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll b/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll index 231e6e4dc9b8..9f20a5fb6447 100644 --- a/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll +++ b/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll @@ -44,7 +44,7 @@ module TaintedUrlSuffix { */ predicate isBarrier(Node node, FlowLabel label) { label = label() and - DataFlowPrivate::optionalBarrier(node, "tainted-url-suffix") + DataFlowPrivate::optionalBarrier(node, "split-url-suffix") } /** @@ -55,7 +55,11 @@ module TaintedUrlSuffix { predicate step(Node src, Node dst, FlowLabel srclbl, FlowLabel dstlbl) { srclbl = label() and dstlbl.isTaint() and - DataFlowPrivate::optionalStep(src, "tainted-url-suffix", dst) + DataFlowPrivate::optionalStep(src, "split-url-suffix-post", dst) + or + srclbl = label() and + dstlbl = label() and + DataFlowPrivate::optionalStep(src, "split-url-suffix-pre", dst) or // Transition from URL suffix to full taint when extracting the query/fragment part. srclbl = label() and diff --git a/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js b/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js index 80d80597e8af..8f08dce92509 100644 --- a/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js +++ b/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js @@ -5,14 +5,14 @@ function t1() { sink(href); // $ flow=tainted-url-suffix - sink(href.split('#')[0]); // $ MISSING: flow=tainted-url-suffix + sink(href.split('#')[0]); // $ flow=tainted-url-suffix sink(href.split('#')[1]); // $ flow=taint - sink(href.split('#').pop()); // $ flow=taint + sink(href.split('#').pop()); // $ flow=taint flow=tainted-url-suffix sink(href.split('#')[2]); // $ MISSING: flow=taint // currently the split() summary only propagates to index 1 - sink(href.split('?')[0]); // $ MISSING: flow=tainted-url-suffix + sink(href.split('?')[0]); // $ flow=tainted-url-suffix sink(href.split('?')[1]); // $ flow=taint - sink(href.split('?').pop()); // $ flow=taint + sink(href.split('?').pop()); // $ flow=taint flow=tainted-url-suffix sink(href.split('?')[2]); // $ MISSING: flow=taint sink(href.split(blah())[0]); // $ flow=tainted-url-suffix From 1df69ec1d22112ec380e7a0ce250426619db2d02 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 12 Sep 2024 13:16:52 +0200 Subject: [PATCH 24/25] JS: Actually don't propagate into array element 0 Preserving tainted-url-suffix into array element 0 seemed like a good idea, but didn't work out so well. --- .../javascript/security/TaintedUrlSuffix.qll | 12 +- .../library-tests/TaintedUrlSuffix/tst.js | 8 +- .../Security/CWE-079/DomBasedXss/Xss.expected | 112 ++--------------- .../XssWithAdditionalSources.expected | 116 ++---------------- .../Security/CWE-079/DomBasedXss/tst.js | 2 +- 5 files changed, 34 insertions(+), 216 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll b/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll index 9f20a5fb6447..0158b1466798 100644 --- a/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll +++ b/javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll @@ -53,14 +53,18 @@ module TaintedUrlSuffix { * This handles steps through string operations, promises, URL parsers, and URL accessors. */ predicate step(Node src, Node dst, FlowLabel srclbl, FlowLabel dstlbl) { + // Transition from tainted-url-suffix to general taint when entering the second array element + // of a split('#') or split('?') array. + // + // x [tainted-url-suffix] --> x.split('#') [array element 1] [taint] + // + // Technically we should also preverse tainted-url-suffix when entering the first array element of such + // a split, but this mostly leads to FPs since we currently don't track if the taint has been through URI-decoding. + // (The query/fragment parts are often URI-decoded in practice, but not the other URL parts are not) srclbl = label() and dstlbl.isTaint() and DataFlowPrivate::optionalStep(src, "split-url-suffix-post", dst) or - srclbl = label() and - dstlbl = label() and - DataFlowPrivate::optionalStep(src, "split-url-suffix-pre", dst) - or // Transition from URL suffix to full taint when extracting the query/fragment part. srclbl = label() and dstlbl.isTaint() and diff --git a/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js b/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js index 8f08dce92509..0c755ac65128 100644 --- a/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js +++ b/javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js @@ -5,14 +5,14 @@ function t1() { sink(href); // $ flow=tainted-url-suffix - sink(href.split('#')[0]); // $ flow=tainted-url-suffix + sink(href.split('#')[0]); // could be 'tainted-url-suffix', but omitted due to FPs from URI-encoding sink(href.split('#')[1]); // $ flow=taint - sink(href.split('#').pop()); // $ flow=taint flow=tainted-url-suffix + sink(href.split('#').pop()); // $ flow=taint sink(href.split('#')[2]); // $ MISSING: flow=taint // currently the split() summary only propagates to index 1 - sink(href.split('?')[0]); // $ flow=tainted-url-suffix + sink(href.split('?')[0]); sink(href.split('?')[1]); // $ flow=taint - sink(href.split('?').pop()); // $ flow=taint flow=tainted-url-suffix + sink(href.split('?').pop()); // $ flow=taint sink(href.split('?')[2]); // $ MISSING: flow=taint sink(href.split(blah())[0]); // $ flow=tainted-url-suffix 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 1e35f0d6edb8..922118ef84bc 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 @@ -4,7 +4,6 @@ nodes | addEventListener.js:2:20:2:29 | event.data | semmle.label | event.data | | addEventListener.js:5:43:5:48 | data | semmle.label | data | | addEventListener.js:5:43:5:48 | {data} | semmle.label | {data} | -| addEventListener.js:5:44:5:47 | data | semmle.label | data | | addEventListener.js:6:20:6:23 | data | semmle.label | data | | addEventListener.js:10:21:10:25 | event | semmle.label | event | | addEventListener.js:12:24:12:28 | event | semmle.label | event | @@ -189,9 +188,7 @@ nodes | jquery.js:37:31:37:37 | tainted | semmle.label | tainted | | json-stringify.jsx:5:9:5:36 | locale | semmle.label | locale | | json-stringify.jsx:5:18:5:36 | req.param("locale") | semmle.label | req.param("locale") | -| json-stringify.jsx:11:16:11:58 | `https: ... ocale}` | semmle.label | `https: ... ocale}` | | json-stringify.jsx:11:51:11:56 | locale | semmle.label | locale | -| json-stringify.jsx:19:16:19:63 | `https: ... ocale}` | semmle.label | `https: ... ocale}` | | json-stringify.jsx:19:56:19:61 | locale | semmle.label | locale | | json-stringify.jsx:31:40:31:61 | JSON.st ... locale) | semmle.label | JSON.st ... locale) | | json-stringify.jsx:31:55:31:60 | locale | semmle.label | locale | @@ -239,7 +236,6 @@ nodes | pages/[id].jsx:3:30:3:35 | params [q] | semmle.label | params [q] | | pages/[id].jsx:5:9:5:14 | { id } | semmle.label | { id } | | pages/[id].jsx:5:9:5:29 | id | semmle.label | id | -| pages/[id].jsx:5:11:5:12 | id | semmle.label | id | | pages/[id].jsx:5:18:5:29 | router.query | semmle.label | router.query | | pages/[id].jsx:10:44:10:45 | id | semmle.label | id | | pages/[id].jsx:13:44:13:49 | params [id] | semmle.label | params [id] | @@ -249,10 +245,8 @@ nodes | pages/[id].jsx:24:12:27:5 | {\\n ... ,\\n } [id] | semmle.label | {\\n ... ,\\n } [id] | | pages/[id].jsx:24:12:27:5 | {\\n ... ,\\n } [q] | semmle.label | {\\n ... ,\\n } [q] | | pages/[id].jsx:25:11:25:24 | context.params | semmle.label | context.params | -| pages/[id].jsx:25:11:25:27 | context.params.id | semmle.label | context.params.id | | pages/[id].jsx:25:11:25:33 | context ... d \|\| "" | semmle.label | context ... d \|\| "" | | pages/[id].jsx:26:10:26:22 | context.query | semmle.label | context.query | -| pages/[id].jsx:26:10:26:30 | context ... .foobar | semmle.label | context ... .foobar | | pages/[id].jsx:26:10:26:36 | context ... r \|\| "" | semmle.label | context ... r \|\| "" | | react-native.js:7:7:7:33 | tainted | semmle.label | tainted | | react-native.js:7:17:7:33 | req.param("code") | semmle.label | req.param("code") | @@ -273,11 +267,9 @@ nodes | react-use-router.js:33:21:33:32 | router.query | semmle.label | router.query | | react-use-router.js:33:21:33:39 | router.query.foobar | semmle.label | router.query.foobar | | react-use-state.js:4:9:4:49 | state | semmle.label | state | -| react-use-state.js:4:10:4:14 | state | semmle.label | state | | react-use-state.js:4:38:4:48 | window.name | semmle.label | window.name | | react-use-state.js:5:51:5:55 | state | semmle.label | state | | react-use-state.js:9:9:9:43 | state | semmle.label | state | -| react-use-state.js:9:10:9:14 | state | semmle.label | state | | react-use-state.js:10:14:10:24 | window.name | semmle.label | window.name | | react-use-state.js:11:51:11:55 | state | semmle.label | state | | react-use-state.js:15:9:15:43 | state | semmle.label | state | @@ -616,7 +608,6 @@ nodes | various-concat-obfuscations.js:15:10:15:83 | '
' | semmle.label | '
' | | various-concat-obfuscations.js:15:27:15:55 | (attrs. ... 'left') | semmle.label | (attrs. ... 'left') | | various-concat-obfuscations.js:15:28:15:32 | attrs | semmle.label | attrs | -| various-concat-obfuscations.js:15:28:15:44 | attrs.defaultattr | semmle.label | attrs.defaultattr | | various-concat-obfuscations.js:17:24:17:28 | attrs | semmle.label | attrs | | various-concat-obfuscations.js:18:10:18:59 | '
') | 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' | | various-concat-obfuscations.js:20:4:20:47 | indirec ... .attrs) | semmle.label | indirec ... .attrs) | | various-concat-obfuscations.js:20:17:20:40 | documen ... .search | semmle.label | documen ... .search | @@ -642,8 +632,7 @@ edges | addEventListener.js:1:43:1:47 | event | addEventListener.js:2:20:2:24 | event | provenance | | | addEventListener.js:2:20:2:24 | event | addEventListener.js:2:20:2:29 | event.data | provenance | | | addEventListener.js:5:43:5:48 | data | addEventListener.js:6:20:6:23 | data | provenance | | -| addEventListener.js:5:43:5:48 | {data} | addEventListener.js:5:44:5:47 | data | provenance | | -| addEventListener.js:5:44:5:47 | data | addEventListener.js:5:43:5:48 | data | provenance | | +| addEventListener.js:5:43:5:48 | {data} | addEventListener.js:5:43:5:48 | data | provenance | | | addEventListener.js:10:21:10:25 | event | addEventListener.js:12:24:12:28 | event | provenance | | | addEventListener.js:12:24:12:28 | event | addEventListener.js:12:24:12:33 | event.data | provenance | | | angular2-client.ts:24:44:24:69 | this.ro ... .params | angular2-client.ts:24:44:24:73 | this.ro ... ams.foo | provenance | | @@ -689,31 +678,18 @@ edges | dates.js:9:36:9:55 | window.location.hash | dates.js:9:36:9:68 | window. ... ring(1) | provenance | | | dates.js:9:36:9:55 | window.location.hash | dates.js:9:36:9:68 | window. ... ring(1) | provenance | Config | | dates.js:9:36:9:68 | window. ... ring(1) | dates.js:9:17:9:69 | decodeU ... ing(1)) | provenance | | -| dates.js:9:36:9:68 | window. ... ring(1) | dates.js:9:17:9:69 | decodeU ... ing(1)) | provenance | Config | | dates.js:11:42:11:68 | dateFns ... taint) | dates.js:11:31:11:70 | `Time i ... aint)}` | provenance | | -| dates.js:11:42:11:68 | dateFns ... taint) | dates.js:11:31:11:70 | `Time i ... aint)}` | provenance | Config | | dates.js:11:63:11:67 | taint | dates.js:11:42:11:68 | dateFns ... taint) | provenance | | -| dates.js:11:63:11:67 | taint | dates.js:11:42:11:68 | dateFns ... taint) | provenance | Config | | dates.js:12:42:12:71 | dateFns ... taint) | dates.js:12:31:12:73 | `Time i ... aint)}` | provenance | | -| dates.js:12:42:12:71 | dateFns ... taint) | dates.js:12:31:12:73 | `Time i ... aint)}` | provenance | Config | | dates.js:12:66:12:70 | taint | dates.js:12:42:12:71 | dateFns ... taint) | provenance | | -| dates.js:12:66:12:70 | taint | dates.js:12:42:12:71 | dateFns ... taint) | provenance | Config | | dates.js:13:42:13:70 | dateFns ... )(time) | dates.js:13:31:13:72 | `Time i ... time)}` | provenance | | -| dates.js:13:42:13:70 | dateFns ... )(time) | dates.js:13:31:13:72 | `Time i ... time)}` | provenance | Config | | dates.js:13:59:13:63 | taint | dates.js:13:42:13:70 | dateFns ... )(time) | provenance | | -| dates.js:13:59:13:63 | taint | dates.js:13:42:13:70 | dateFns ... )(time) | provenance | Config | | dates.js:16:42:16:67 | moment( ... (taint) | dates.js:16:31:16:69 | `Time i ... aint)}` | provenance | | -| dates.js:16:42:16:67 | moment( ... (taint) | dates.js:16:31:16:69 | `Time i ... aint)}` | provenance | Config | | dates.js:16:62:16:66 | taint | dates.js:16:42:16:67 | moment( ... (taint) | provenance | | -| dates.js:16:62:16:66 | taint | dates.js:16:42:16:67 | moment( ... (taint) | provenance | Config | | dates.js:18:42:18:64 | datefor ... taint) | dates.js:18:31:18:66 | `Time i ... aint)}` | provenance | | -| dates.js:18:42:18:64 | datefor ... taint) | dates.js:18:31:18:66 | `Time i ... aint)}` | provenance | Config | | dates.js:18:59:18:63 | taint | dates.js:18:42:18:64 | datefor ... taint) | provenance | | -| dates.js:18:59:18:63 | taint | dates.js:18:42:18:64 | datefor ... taint) | provenance | Config | | dates.js:21:42:21:66 | dayjs(t ... (taint) | dates.js:21:31:21:68 | `Time i ... aint)}` | provenance | | -| dates.js:21:42:21:66 | dayjs(t ... (taint) | dates.js:21:31:21:68 | `Time i ... aint)}` | provenance | Config | | dates.js:21:61:21:65 | taint | dates.js:21:42:21:66 | dayjs(t ... (taint) | provenance | | -| dates.js:21:61:21:65 | taint | dates.js:21:42:21:66 | dayjs(t ... (taint) | provenance | Config | | dates.js:30:9:30:69 | taint | dates.js:37:77:37:81 | taint | provenance | | | dates.js:30:9:30:69 | taint | dates.js:38:77:38:81 | taint | provenance | | | dates.js:30:9:30:69 | taint | dates.js:39:79:39:83 | taint | provenance | | @@ -722,23 +698,14 @@ edges | dates.js:30:36:30:55 | window.location.hash | dates.js:30:36:30:68 | window. ... ring(1) | provenance | | | dates.js:30:36:30:55 | window.location.hash | dates.js:30:36:30:68 | window. ... ring(1) | provenance | Config | | dates.js:30:36:30:68 | window. ... ring(1) | dates.js:30:17:30:69 | decodeU ... ing(1)) | provenance | | -| dates.js:30:36:30:68 | window. ... ring(1) | dates.js:30:17:30:69 | decodeU ... ing(1)) | provenance | Config | | dates.js:37:42:37:82 | dateFns ... taint) | dates.js:37:31:37:84 | `Time i ... aint)}` | provenance | | -| dates.js:37:42:37:82 | dateFns ... taint) | dates.js:37:31:37:84 | `Time i ... aint)}` | provenance | Config | | dates.js:37:77:37:81 | taint | dates.js:37:42:37:82 | dateFns ... taint) | provenance | | -| dates.js:37:77:37:81 | taint | dates.js:37:42:37:82 | dateFns ... taint) | provenance | Config | | dates.js:38:42:38:82 | luxon.f ... taint) | dates.js:38:31:38:84 | `Time i ... aint)}` | provenance | | -| dates.js:38:42:38:82 | luxon.f ... taint) | dates.js:38:31:38:84 | `Time i ... aint)}` | provenance | Config | | dates.js:38:77:38:81 | taint | dates.js:38:42:38:82 | luxon.f ... taint) | provenance | | -| dates.js:38:77:38:81 | taint | dates.js:38:42:38:82 | luxon.f ... taint) | provenance | Config | | dates.js:39:42:39:84 | moment. ... taint) | dates.js:39:31:39:86 | `Time i ... aint)}` | provenance | | -| dates.js:39:42:39:84 | moment. ... taint) | dates.js:39:31:39:86 | `Time i ... aint)}` | provenance | Config | | dates.js:39:79:39:83 | taint | dates.js:39:42:39:84 | moment. ... taint) | provenance | | -| dates.js:39:79:39:83 | taint | dates.js:39:42:39:84 | moment. ... taint) | provenance | Config | | dates.js:40:42:40:82 | dayjs.f ... taint) | dates.js:40:31:40:84 | `Time i ... aint)}` | provenance | | -| dates.js:40:42:40:82 | dayjs.f ... taint) | dates.js:40:31:40:84 | `Time i ... aint)}` | provenance | Config | | dates.js:40:77:40:81 | taint | dates.js:40:42:40:82 | dayjs.f ... taint) | provenance | | -| dates.js:40:77:40:81 | taint | dates.js:40:42:40:82 | dayjs.f ... taint) | provenance | Config | | dates.js:46:9:46:69 | taint | dates.js:48:83:48:87 | taint | provenance | | | dates.js:46:9:46:69 | taint | dates.js:49:82:49:86 | taint | provenance | | | dates.js:46:9:46:69 | taint | dates.js:50:97:50:101 | taint | provenance | | @@ -746,19 +713,12 @@ edges | dates.js:46:36:46:55 | window.location.hash | dates.js:46:36:46:68 | window. ... ring(1) | provenance | | | dates.js:46:36:46:55 | window.location.hash | dates.js:46:36:46:68 | window. ... ring(1) | provenance | Config | | dates.js:46:36:46:68 | window. ... ring(1) | dates.js:46:17:46:69 | decodeU ... ing(1)) | provenance | | -| dates.js:46:36:46:68 | window. ... ring(1) | dates.js:46:17:46:69 | decodeU ... ing(1)) | provenance | Config | | dates.js:48:42:48:88 | DateTim ... (taint) | dates.js:48:31:48:90 | `Time i ... aint)}` | provenance | | -| dates.js:48:42:48:88 | DateTim ... (taint) | dates.js:48:31:48:90 | `Time i ... aint)}` | provenance | Config | | dates.js:48:83:48:87 | taint | dates.js:48:42:48:88 | DateTim ... (taint) | provenance | | -| dates.js:48:83:48:87 | taint | dates.js:48:42:48:88 | DateTim ... (taint) | provenance | Config | | dates.js:49:42:49:87 | new Dat ... (taint) | dates.js:49:31:49:89 | `Time i ... aint)}` | provenance | | -| dates.js:49:42:49:87 | new Dat ... (taint) | dates.js:49:31:49:89 | `Time i ... aint)}` | provenance | Config | | dates.js:49:82:49:86 | taint | dates.js:49:42:49:87 | new Dat ... (taint) | provenance | | -| dates.js:49:82:49:86 | taint | dates.js:49:42:49:87 | new Dat ... (taint) | provenance | Config | | dates.js:50:42:50:102 | DateTim ... (taint) | dates.js:50:31:50:104 | `Time i ... aint)}` | provenance | | -| dates.js:50:42:50:102 | DateTim ... (taint) | dates.js:50:31:50:104 | `Time i ... aint)}` | provenance | Config | | dates.js:50:97:50:101 | taint | dates.js:50:42:50:102 | DateTim ... (taint) | provenance | | -| dates.js:50:97:50:101 | taint | dates.js:50:42:50:102 | DateTim ... (taint) | provenance | Config | | dates.js:54:9:54:69 | taint | dates.js:57:94:57:98 | taint | provenance | | | dates.js:54:9:54:69 | taint | dates.js:59:80:59:84 | taint | provenance | | | dates.js:54:9:54:69 | taint | dates.js:61:81:61:85 | taint | provenance | | @@ -766,19 +726,12 @@ edges | dates.js:54:36:54:55 | window.location.hash | dates.js:54:36:54:68 | window. ... ring(1) | provenance | | | dates.js:54:36:54:55 | window.location.hash | dates.js:54:36:54:68 | window. ... ring(1) | provenance | Config | | dates.js:54:36:54:68 | window. ... ring(1) | dates.js:54:17:54:69 | decodeU ... ing(1)) | provenance | | -| dates.js:54:36:54:68 | window. ... ring(1) | dates.js:54:17:54:69 | decodeU ... ing(1)) | provenance | Config | | dates.js:57:42:57:99 | moment. ... (taint) | dates.js:57:31:57:101 | `Time i ... aint)}` | provenance | | -| dates.js:57:42:57:99 | moment. ... (taint) | dates.js:57:31:57:101 | `Time i ... aint)}` | provenance | Config | | dates.js:57:94:57:98 | taint | dates.js:57:42:57:99 | moment. ... (taint) | provenance | | -| dates.js:57:94:57:98 | taint | dates.js:57:42:57:99 | moment. ... (taint) | provenance | Config | | dates.js:59:42:59:85 | luxon.e ... (taint) | dates.js:59:31:59:87 | `Time i ... aint)}` | provenance | | -| dates.js:59:42:59:85 | luxon.e ... (taint) | dates.js:59:31:59:87 | `Time i ... aint)}` | provenance | Config | | dates.js:59:80:59:84 | taint | dates.js:59:42:59:85 | luxon.e ... (taint) | provenance | | -| dates.js:59:80:59:84 | taint | dates.js:59:42:59:85 | luxon.e ... (taint) | provenance | Config | | dates.js:61:42:61:86 | dayjs.s ... (taint) | dates.js:61:31:61:88 | `Time i ... aint)}` | provenance | | -| dates.js:61:42:61:86 | dayjs.s ... (taint) | dates.js:61:31:61:88 | `Time i ... aint)}` | provenance | Config | | dates.js:61:81:61:85 | taint | dates.js:61:42:61:86 | dayjs.s ... (taint) | provenance | | -| dates.js:61:81:61:85 | taint | dates.js:61:42:61:86 | dayjs.s ... (taint) | provenance | Config | | dragAndDrop.ts:8:11:8:50 | html | dragAndDrop.ts:15:25:15:28 | html | provenance | | | dragAndDrop.ts:8:18:8:50 | dataTra ... /html') | dragAndDrop.ts:8:11:8:50 | html | provenance | | | dragAndDrop.ts:43:15:43:54 | html | dragAndDrop.ts:50:29:50:32 | html | provenance | | @@ -794,18 +747,12 @@ edges | jquery.js:2:17:2:40 | documen ... .search | jquery.js:2:7:2:40 | tainted | provenance | | | jquery.js:7:20:7:26 | tainted | jquery.js:7:5:7:34 | "
" | provenance | Config | | jquery.js:8:28:8:34 | tainted | jquery.js:8:18:8:34 | "XSS: " + tainted | provenance | | -| jquery.js:8:28:8:34 | tainted | jquery.js:8:18:8:34 | "XSS: " + tainted | provenance | Config | | jquery.js:10:13:10:20 | location | jquery.js:10:13:10:31 | location.toString() | provenance | | -| jquery.js:10:13:10:20 | location | jquery.js:10:13:10:31 | location.toString() | provenance | Config | | jquery.js:10:13:10:31 | location.toString() | jquery.js:10:5:10:40 | "" + ... "" | provenance | Config | | jquery.js:14:38:14:57 | window.location.hash | jquery.js:14:19:14:58 | decodeU ... n.hash) | provenance | | -| jquery.js:14:38:14:57 | window.location.hash | jquery.js:14:19:14:58 | decodeU ... n.hash) | provenance | Config | | jquery.js:15:38:15:59 | window. ... .search | jquery.js:15:19:15:60 | decodeU ... search) | provenance | | -| jquery.js:15:38:15:59 | window. ... .search | jquery.js:15:19:15:60 | decodeU ... search) | provenance | Config | | jquery.js:16:38:16:52 | window.location | jquery.js:16:38:16:63 | window. ... tring() | provenance | | -| jquery.js:16:38:16:52 | window.location | jquery.js:16:38:16:63 | window. ... tring() | provenance | Config | | jquery.js:16:38:16:63 | window. ... tring() | jquery.js:16:19:16:64 | decodeU ... ring()) | provenance | | -| jquery.js:16:38:16:63 | window. ... tring() | jquery.js:16:19:16:64 | decodeU ... ring()) | provenance | Config | | jquery.js:18:7:18:33 | hash | jquery.js:21:5:21:8 | hash | provenance | | | jquery.js:18:7:18:33 | hash | jquery.js:22:5:22:8 | hash | provenance | | | jquery.js:18:7:18:33 | hash | jquery.js:23:5:23:8 | hash | provenance | | @@ -825,10 +772,8 @@ edges | json-stringify.jsx:5:9:5:36 | locale | json-stringify.jsx:19:56:19:61 | locale | provenance | | | json-stringify.jsx:5:9:5:36 | locale | json-stringify.jsx:31:55:31:60 | locale | provenance | | | json-stringify.jsx:5:18:5:36 | req.param("locale") | json-stringify.jsx:5:9:5:36 | locale | provenance | | -| json-stringify.jsx:11:16:11:58 | `https: ... ocale}` | json-stringify.jsx:35:40:35:61 | JSON.st ... jsonLD) | provenance | | -| json-stringify.jsx:11:51:11:56 | locale | json-stringify.jsx:11:16:11:58 | `https: ... ocale}` | provenance | | -| json-stringify.jsx:19:16:19:63 | `https: ... ocale}` | json-stringify.jsx:35:40:35:61 | JSON.st ... jsonLD) | provenance | | -| json-stringify.jsx:19:56:19:61 | locale | json-stringify.jsx:19:16:19:63 | `https: ... ocale}` | provenance | | +| json-stringify.jsx:11:51:11:56 | locale | json-stringify.jsx:35:40:35:61 | JSON.st ... jsonLD) | provenance | | +| json-stringify.jsx:19:56:19:61 | locale | json-stringify.jsx:35:40:35:61 | JSON.st ... jsonLD) | provenance | | | json-stringify.jsx:31:55:31:60 | locale | json-stringify.jsx:31:40:31:61 | JSON.st ... locale) | provenance | | | jwt-server.js:7:9:7:35 | taint | jwt-server.js:9:16:9:20 | taint | provenance | | | jwt-server.js:7:17:7:35 | req.param("wobble") | jwt-server.js:7:9:7:35 | taint | provenance | | @@ -872,19 +817,16 @@ edges | optionalSanitizer.js:45:51:45:56 | target | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | provenance | | | pages/[id].jsx:3:30:3:35 | params [id] | pages/[id].jsx:13:44:13:49 | params [id] | provenance | | | pages/[id].jsx:3:30:3:35 | params [q] | pages/[id].jsx:16:44:16:49 | params [q] | provenance | | -| pages/[id].jsx:5:9:5:14 | { id } | pages/[id].jsx:5:11:5:12 | id | provenance | | +| pages/[id].jsx:5:9:5:14 | { id } | pages/[id].jsx:5:9:5:29 | id | provenance | | | pages/[id].jsx:5:9:5:29 | id | pages/[id].jsx:10:44:10:45 | id | provenance | | -| pages/[id].jsx:5:11:5:12 | id | pages/[id].jsx:5:9:5:29 | id | provenance | | | pages/[id].jsx:5:18:5:29 | router.query | pages/[id].jsx:5:9:5:14 | { id } | provenance | | | pages/[id].jsx:13:44:13:49 | params [id] | pages/[id].jsx:13:44:13:52 | params.id | provenance | | | pages/[id].jsx:16:44:16:49 | params [q] | pages/[id].jsx:16:44:16:51 | params.q | provenance | | | pages/[id].jsx:24:12:27:5 | {\\n ... ,\\n } [id] | pages/[id].jsx:3:30:3:35 | params [id] | provenance | | | pages/[id].jsx:24:12:27:5 | {\\n ... ,\\n } [q] | pages/[id].jsx:3:30:3:35 | params [q] | provenance | | -| pages/[id].jsx:25:11:25:24 | context.params | pages/[id].jsx:25:11:25:27 | context.params.id | provenance | | -| pages/[id].jsx:25:11:25:27 | context.params.id | pages/[id].jsx:25:11:25:33 | context ... d \|\| "" | provenance | | +| pages/[id].jsx:25:11:25:24 | context.params | pages/[id].jsx:25:11:25:33 | context ... d \|\| "" | provenance | | | pages/[id].jsx:25:11:25:33 | context ... d \|\| "" | pages/[id].jsx:24:12:27:5 | {\\n ... ,\\n } [id] | provenance | | -| pages/[id].jsx:26:10:26:22 | context.query | pages/[id].jsx:26:10:26:30 | context ... .foobar | provenance | | -| pages/[id].jsx:26:10:26:30 | context ... .foobar | pages/[id].jsx:26:10:26:36 | context ... r \|\| "" | provenance | | +| pages/[id].jsx:26:10:26:22 | context.query | pages/[id].jsx:26:10:26:36 | context ... r \|\| "" | provenance | | | pages/[id].jsx:26:10:26:36 | context ... r \|\| "" | pages/[id].jsx:24:12:27:5 | {\\n ... ,\\n } [q] | provenance | | | react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted | provenance | | | react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted | provenance | | @@ -900,11 +842,9 @@ edges | 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 | | -| react-use-state.js:4:38:4:48 | window.name | react-use-state.js:4:10:4:14 | state | provenance | | +| react-use-state.js:4:38:4:48 | window.name | react-use-state.js:4:9:4:49 | state | provenance | | | react-use-state.js:9:9:9:43 | state | react-use-state.js:11:51:11:55 | state | provenance | | -| react-use-state.js:9:10:9:14 | state | react-use-state.js:9:9:9:43 | state | provenance | | -| react-use-state.js:10:14:10:24 | window.name | react-use-state.js:9:10:9:14 | state | provenance | | +| react-use-state.js:10:14:10:24 | window.name | react-use-state.js:9:9:9:43 | state | provenance | | | react-use-state.js:15:9:15:43 | state | react-use-state.js:17:51:17:55 | state | provenance | | | react-use-state.js:15:10:15:14 | state | react-use-state.js:15:9:15:43 | state | provenance | | | react-use-state.js:16:20:16:30 | window.name | react-use-state.js:15:10:15:14 | state | provenance | | @@ -931,27 +871,18 @@ edges | sanitiser.js:45:29:45:35 | tainted | sanitiser.js:45:21:45:44 | '' + ... '' | provenance | | | sanitiser.js:48:19:48:25 | tainted | sanitiser.js:48:19:48:46 | tainted ... /g, '') | provenance | | | stored-xss.js:2:39:2:62 | documen ... .search | stored-xss.js:5:20:5:52 | session ... ssion') | provenance | | -| stored-xss.js:2:39:2:62 | documen ... .search | stored-xss.js:5:20:5:52 | session ... ssion') | provenance | Config | | stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:8:20:8:48 | localSt ... local') | provenance | | -| stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:8:20:8:48 | localSt ... local') | provenance | Config | | stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:10:16:10:44 | localSt ... local') | provenance | | -| stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:10:16:10:44 | localSt ... local') | provenance | Config | | stored-xss.js:10:9:10:44 | href | stored-xss.js:12:35:12:38 | href | provenance | | | stored-xss.js:10:16:10:44 | localSt ... local') | stored-xss.js:10:9:10:44 | href | provenance | | | stored-xss.js:12:35:12:38 | href | stored-xss.js:12:20:12:54 | "" | provenance | | | stored-xss.js:12:35:12:38 | href | stored-xss.js:12:20:12:54 | "" | provenance | Config | | string-manipulations.js:5:16:5:37 | documen ... on.href | string-manipulations.js:5:16:5:47 | documen ... lueOf() | provenance | | -| string-manipulations.js:5:16:5:37 | documen ... on.href | string-manipulations.js:5:16:5:47 | documen ... lueOf() | provenance | Config | | string-manipulations.js:6:16:6:37 | documen ... on.href | string-manipulations.js:6:16:6:43 | documen ... f.sup() | provenance | | -| string-manipulations.js:6:16:6:37 | documen ... on.href | string-manipulations.js:6:16:6:43 | documen ... f.sup() | provenance | Config | | string-manipulations.js:7:16:7:37 | documen ... on.href | string-manipulations.js:7:16:7:51 | documen ... rCase() | provenance | | -| string-manipulations.js:7:16:7:37 | documen ... on.href | string-manipulations.js:7:16:7:51 | documen ... rCase() | provenance | Config | | string-manipulations.js:8:16:8:37 | documen ... on.href | string-manipulations.js:8:16:8:48 | documen ... mLeft() | provenance | | -| string-manipulations.js:8:16:8:37 | documen ... on.href | string-manipulations.js:8:16:8:48 | documen ... mLeft() | provenance | Config | | string-manipulations.js:9:36:9:57 | documen ... on.href | string-manipulations.js:9:16:9:58 | String. ... n.href) | provenance | | -| 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:17:3:17 | y | tainted-url-suffix-arguments.js:6:22:6:22 | y | 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 | | @@ -967,7 +898,6 @@ edges | translate.js:7:7:7:61 | searchParams | translate.js:9:27:9:38 | searchParams | provenance | | | translate.js:7:22:7:61 | new URL ... ing(1)) | translate.js:7:7:7:61 | searchParams | provenance | | | translate.js:7:42:7:47 | target | translate.js:7:42:7:60 | target.substring(1) | provenance | | -| translate.js:7:42:7:47 | target | translate.js:7:42:7:60 | target.substring(1) | provenance | Config | | translate.js:7:42:7:60 | target.substring(1) | translate.js:7:22:7:61 | new URL ... ing(1)) | provenance | | | translate.js:9:27:9:38 | searchParams | translate.js:9:27:9:50 | searchP ... 'term') | provenance | Config | | trusted-types-lib.js:1:28:1:28 | x | trusted-types-lib.js:2:12:2:12 | x | provenance | | @@ -1005,7 +935,6 @@ edges | tst.js:20:7:20:61 | searchParams | tst.js:21:18:21:29 | searchParams | provenance | | | tst.js:20:22:20:61 | new URL ... ing(1)) | tst.js:20:7:20:61 | searchParams | provenance | | | tst.js:20:42:20:47 | target | tst.js:20:42:20:60 | target.substring(1) | provenance | | -| tst.js:20:42:20:47 | target | tst.js:20:42:20:60 | target.substring(1) | provenance | Config | | tst.js:20:42:20:60 | target.substring(1) | tst.js:20:22:20:61 | new URL ... ing(1)) | provenance | | | tst.js:21:18:21:29 | searchParams | tst.js:21:18:21:41 | searchP ... 'name') | provenance | Config | | tst.js:24:14:24:19 | target | tst.js:26:18:26:23 | target | provenance | | @@ -1073,19 +1002,14 @@ edges | tst.js:197:9:197:42 | tainted | tst.js:255:23:255:29 | tainted | provenance | | | tst.js:197:19:197:42 | documen ... .search | tst.js:197:9:197:42 | tainted | provenance | | | tst.js:204:35:204:41 | tainted | tst.js:212:28:212:46 | this.state.tainted1 | provenance | | -| tst.js:204:35:204:41 | tainted | tst.js:212:28:212:46 | this.state.tainted1 | provenance | Config | | tst.js:206:46:206:52 | tainted | tst.js:213:28:213:46 | this.state.tainted2 | provenance | | -| tst.js:206:46:206:52 | tainted | tst.js:213:28:213:46 | this.state.tainted2 | provenance | Config | | tst.js:207:38:207:44 | tainted | tst.js:214:28:214:46 | this.state.tainted3 | provenance | | -| tst.js:207:38:207:44 | tainted | tst.js:214:28:214:46 | this.state.tainted3 | provenance | Config | | tst.js:208:35:208:41 | tainted | tst.js:218:32:218:49 | prevState.tainted4 | provenance | | -| tst.js:208:35:208:41 | tainted | tst.js:218:32:218:49 | prevState.tainted4 | provenance | Config | | tst.js:236:35:236:41 | tainted | tst.js:225:28:225:46 | this.props.tainted1 | provenance | | | tst.js:238:20:238:26 | tainted | tst.js:226:28:226:46 | this.props.tainted2 | provenance | | | tst.js:240:23:240:29 | tainted | tst.js:227:28:227:46 | this.props.tainted3 | provenance | | | tst.js:241:23:241:29 | tainted | tst.js:231:32:231:49 | prevProps.tainted4 | provenance | | | tst.js:247:39:247:55 | props.propTainted | tst.js:251:60:251:82 | this.st ... Tainted | provenance | | -| tst.js:247:39:247:55 | props.propTainted | tst.js:251:60:251:82 | this.st ... Tainted | provenance | Config | | tst.js:255:23:255:29 | tainted | tst.js:247:39:247:55 | props.propTainted | provenance | | | tst.js:285:9:285:29 | tainted | tst.js:288:59:288:65 | tainted | provenance | | | tst.js:285:19:285:29 | window.name | tst.js:285:9:285:29 | tainted | provenance | | @@ -1121,17 +1045,13 @@ edges | tst.js:381:7:381:39 | target [taint8] | tst.js:409:18:409:23 | target [taint8] | provenance | | | tst.js:381:16:381:39 | documen ... .search | tst.js:381:7:381:39 | target | provenance | | | tst.js:386:18:386:23 | target | tst.js:386:18:386:29 | target.taint | provenance | | -| tst.js:386:18:386:23 | target | tst.js:386:18:386:29 | target.taint | provenance | Config | | tst.js:391:3:391:8 | [post update] target [taint3] | tst.js:381:7:381:39 | target [taint3] | provenance | | | tst.js:391:19:391:42 | documen ... .search | tst.js:391:3:391:8 | [post update] target [taint3] | provenance | | | tst.js:392:18:392:23 | target [taint3] | tst.js:392:18:392:30 | target.taint3 | provenance | | | tst.js:397:18:397:23 | target | tst.js:397:18:397:30 | target.taint5 | provenance | | -| tst.js:397:18:397:23 | target | tst.js:397:18:397:30 | target.taint5 | provenance | Config | | tst.js:406:18:406:23 | target | tst.js:406:18:406:30 | target.taint7 | provenance | | -| tst.js:406:18:406:23 | target | tst.js:406:18:406:30 | target.taint7 | provenance | Config | | tst.js:408:3:408:8 | [post update] target [taint8] | tst.js:381:7:381:39 | target [taint8] | provenance | | | tst.js:408:19:408:24 | target | tst.js:408:19:408:31 | target.taint8 | provenance | | -| tst.js:408:19:408:24 | target | tst.js:408:19:408:31 | target.taint8 | provenance | Config | | tst.js:408:19:408:24 | target [taint8] | tst.js:408:19:408:31 | target.taint8 | provenance | | | tst.js:408:19:408:31 | target.taint8 | tst.js:408:3:408:8 | [post update] target [taint8] | provenance | | | tst.js:409:18:409:23 | target [taint8] | tst.js:409:18:409:30 | target.taint8 | provenance | | @@ -1141,16 +1061,13 @@ edges | tst.js:416:17:416:46 | window. ... bstr(1) | tst.js:416:7:416:46 | payload | provenance | | | tst.js:419:7:419:55 | match | tst.js:421:20:421:24 | match | provenance | | | tst.js:419:15:419:34 | window.location.hash | tst.js:419:15:419:55 | window. ... (\\w+)/) | provenance | | -| tst.js:419:15:419:34 | window.location.hash | tst.js:419:15:419:55 | window. ... (\\w+)/) | provenance | Config | | tst.js:419:15:419:55 | window. ... (\\w+)/) | tst.js:419:7:419:55 | match | provenance | | | tst.js:421:20:421:24 | match | tst.js:421:20:421:27 | match[1] | provenance | | -| 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('#') [1] | provenance | Config | | tst.js:424:18:424:48 | window. ... it('#') [1] | tst.js:424:18:424:51 | window. ... '#')[1] | provenance | | | 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 | | -| tst.js:430:18:430:23 | target | tst.js:430:18:430:89 | target. ... data>') | provenance | Config | | tst.js:436:6:436:38 | source | tst.js:440:28:440:33 | source | provenance | | | tst.js:436:6:436:38 | source | tst.js:441:33:441:38 | source | provenance | | | tst.js:436:6:436:38 | source | tst.js:442:34:442:39 | source | provenance | | @@ -1162,7 +1079,6 @@ edges | tst.js:453:7:453:39 | source | tst.js:456:36:456:41 | source | provenance | | | tst.js:453:16:453:39 | documen ... .search | tst.js:453:7:453:39 | source | provenance | | | tst.js:456:36:456:41 | source | tst.js:456:18:456:42 | ansiToH ... source) | provenance | | -| tst.js:456:36:456:41 | source | tst.js:456:18:456:42 | ansiToH ... source) | provenance | Config | | tst.js:460:6:460:38 | source | tst.js:463:21:463:26 | source | provenance | | | tst.js:460:6:460:38 | source | tst.js:465:19:465:24 | source | provenance | | | tst.js:460:6:460:38 | source | tst.js:467:20:467:25 | source | provenance | | @@ -1177,11 +1093,9 @@ edges | tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) | provenance | Config | | tst.js:494:18:494:30 | location.hash | tst.js:494:18:494:40 | locatio ... bstr(1) | provenance | Config | | tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) | provenance | | -| tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) | provenance | Config | | typeahead.js:20:13:20:45 | target | typeahead.js:21:12:21:17 | target | provenance | | | typeahead.js:20:22:20:45 | documen ... .search | typeahead.js:20:13:20:45 | target | provenance | | | typeahead.js:21:12:21:17 | target | typeahead.js:24:30:24:32 | val | provenance | | -| typeahead.js:21:12:21:17 | target | typeahead.js:24:30:24:32 | val | provenance | Config | | typeahead.js:24:30:24:32 | val | typeahead.js:25:18:25:20 | val | provenance | | | various-concat-obfuscations.js:2:6:2:39 | tainted | various-concat-obfuscations.js:4:14:4:20 | tainted | provenance | | | various-concat-obfuscations.js:2:6:2:39 | tainted | various-concat-obfuscations.js:5:12:5:18 | tainted | provenance | | @@ -1210,9 +1124,7 @@ edges | various-concat-obfuscations.js:12:19:12:25 | tainted | various-concat-obfuscations.js:12:4:12:34 | ["
"] | provenance | Config | | various-concat-obfuscations.js:14:24:14:28 | attrs | various-concat-obfuscations.js:15:28:15:32 | attrs | provenance | | | various-concat-obfuscations.js:15:27:15:55 | (attrs. ... 'left') | various-concat-obfuscations.js:15:10:15:83 | '
' | provenance | Config | -| various-concat-obfuscations.js:15:28:15:32 | attrs | various-concat-obfuscations.js:15:28:15:44 | attrs.defaultattr | provenance | | -| various-concat-obfuscations.js:15:28:15:32 | attrs | various-concat-obfuscations.js:15:28:15:44 | attrs.defaultattr | provenance | Config | -| various-concat-obfuscations.js:15:28:15:44 | attrs.defaultattr | various-concat-obfuscations.js:15:27:15:55 | (attrs. ... 'left') | provenance | | +| various-concat-obfuscations.js:15:28:15:32 | attrs | various-concat-obfuscations.js:15:27:15:55 | (attrs. ... 'left') | provenance | | | various-concat-obfuscations.js:17:24:17:28 | attrs | various-concat-obfuscations.js:18:32:18:36 | attrs | provenance | | | various-concat-obfuscations.js:18:10:18:59 | '
') [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 | | +| various-concat-obfuscations.js:18:32:18:36 | attrs | various-concat-obfuscations.js:18:32:18:58 | attrs.d ... 'left' | provenance | | | various-concat-obfuscations.js:18:32:18:58 | attrs.d ... 'left' | various-concat-obfuscations.js:18:10:18:59 | '
' | semmle.label | '
' | | various-concat-obfuscations.js:15:27:15:55 | (attrs. ... 'left') | semmle.label | (attrs. ... 'left') | | various-concat-obfuscations.js:15:28:15:32 | attrs | semmle.label | attrs | -| various-concat-obfuscations.js:15:28:15:44 | attrs.defaultattr | semmle.label | attrs.defaultattr | | various-concat-obfuscations.js:17:24:17:28 | attrs | semmle.label | attrs | | various-concat-obfuscations.js:18:10:18:59 | '
') | 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' | | various-concat-obfuscations.js:20:4:20:47 | indirec ... .attrs) | semmle.label | indirec ... .attrs) | | various-concat-obfuscations.js:20:17:20:40 | documen ... .search | semmle.label | documen ... .search | @@ -656,15 +646,13 @@ nodes | xmlRequest.js:21:11:21:38 | json | semmle.label | json | | xmlRequest.js:21:18:21:38 | JSON.pa ... p.body) | semmle.label | JSON.pa ... p.body) | | xmlRequest.js:21:29:21:32 | resp | semmle.label | resp | -| xmlRequest.js:21:29:21:37 | resp.body | semmle.label | resp.body | | xmlRequest.js:22:24:22:27 | json | semmle.label | json | | xmlRequest.js:22:24:22:35 | json.message | semmle.label | json.message | edges | addEventListener.js:1:43:1:47 | event | addEventListener.js:2:20:2:24 | event | provenance | | | addEventListener.js:2:20:2:24 | event | addEventListener.js:2:20:2:29 | event.data | provenance | | | addEventListener.js:5:43:5:48 | data | addEventListener.js:6:20:6:23 | data | provenance | | -| addEventListener.js:5:43:5:48 | {data} | addEventListener.js:5:44:5:47 | data | provenance | | -| addEventListener.js:5:44:5:47 | data | addEventListener.js:5:43:5:48 | data | provenance | | +| addEventListener.js:5:43:5:48 | {data} | addEventListener.js:5:43:5:48 | data | provenance | | | addEventListener.js:10:21:10:25 | event | addEventListener.js:12:24:12:28 | event | provenance | | | addEventListener.js:12:24:12:28 | event | addEventListener.js:12:24:12:33 | event.data | provenance | | | angular2-client.ts:24:44:24:69 | this.ro ... .params | angular2-client.ts:24:44:24:73 | this.ro ... ams.foo | provenance | | @@ -710,31 +698,18 @@ edges | dates.js:9:36:9:55 | window.location.hash | dates.js:9:36:9:68 | window. ... ring(1) | provenance | | | dates.js:9:36:9:55 | window.location.hash | dates.js:9:36:9:68 | window. ... ring(1) | provenance | Config | | dates.js:9:36:9:68 | window. ... ring(1) | dates.js:9:17:9:69 | decodeU ... ing(1)) | provenance | | -| dates.js:9:36:9:68 | window. ... ring(1) | dates.js:9:17:9:69 | decodeU ... ing(1)) | provenance | Config | | dates.js:11:42:11:68 | dateFns ... taint) | dates.js:11:31:11:70 | `Time i ... aint)}` | provenance | | -| dates.js:11:42:11:68 | dateFns ... taint) | dates.js:11:31:11:70 | `Time i ... aint)}` | provenance | Config | | dates.js:11:63:11:67 | taint | dates.js:11:42:11:68 | dateFns ... taint) | provenance | | -| dates.js:11:63:11:67 | taint | dates.js:11:42:11:68 | dateFns ... taint) | provenance | Config | | dates.js:12:42:12:71 | dateFns ... taint) | dates.js:12:31:12:73 | `Time i ... aint)}` | provenance | | -| dates.js:12:42:12:71 | dateFns ... taint) | dates.js:12:31:12:73 | `Time i ... aint)}` | provenance | Config | | dates.js:12:66:12:70 | taint | dates.js:12:42:12:71 | dateFns ... taint) | provenance | | -| dates.js:12:66:12:70 | taint | dates.js:12:42:12:71 | dateFns ... taint) | provenance | Config | | dates.js:13:42:13:70 | dateFns ... )(time) | dates.js:13:31:13:72 | `Time i ... time)}` | provenance | | -| dates.js:13:42:13:70 | dateFns ... )(time) | dates.js:13:31:13:72 | `Time i ... time)}` | provenance | Config | | dates.js:13:59:13:63 | taint | dates.js:13:42:13:70 | dateFns ... )(time) | provenance | | -| dates.js:13:59:13:63 | taint | dates.js:13:42:13:70 | dateFns ... )(time) | provenance | Config | | dates.js:16:42:16:67 | moment( ... (taint) | dates.js:16:31:16:69 | `Time i ... aint)}` | provenance | | -| dates.js:16:42:16:67 | moment( ... (taint) | dates.js:16:31:16:69 | `Time i ... aint)}` | provenance | Config | | dates.js:16:62:16:66 | taint | dates.js:16:42:16:67 | moment( ... (taint) | provenance | | -| dates.js:16:62:16:66 | taint | dates.js:16:42:16:67 | moment( ... (taint) | provenance | Config | | dates.js:18:42:18:64 | datefor ... taint) | dates.js:18:31:18:66 | `Time i ... aint)}` | provenance | | -| dates.js:18:42:18:64 | datefor ... taint) | dates.js:18:31:18:66 | `Time i ... aint)}` | provenance | Config | | dates.js:18:59:18:63 | taint | dates.js:18:42:18:64 | datefor ... taint) | provenance | | -| dates.js:18:59:18:63 | taint | dates.js:18:42:18:64 | datefor ... taint) | provenance | Config | | dates.js:21:42:21:66 | dayjs(t ... (taint) | dates.js:21:31:21:68 | `Time i ... aint)}` | provenance | | -| dates.js:21:42:21:66 | dayjs(t ... (taint) | dates.js:21:31:21:68 | `Time i ... aint)}` | provenance | Config | | dates.js:21:61:21:65 | taint | dates.js:21:42:21:66 | dayjs(t ... (taint) | provenance | | -| dates.js:21:61:21:65 | taint | dates.js:21:42:21:66 | dayjs(t ... (taint) | provenance | Config | | dates.js:30:9:30:69 | taint | dates.js:37:77:37:81 | taint | provenance | | | dates.js:30:9:30:69 | taint | dates.js:38:77:38:81 | taint | provenance | | | dates.js:30:9:30:69 | taint | dates.js:39:79:39:83 | taint | provenance | | @@ -743,23 +718,14 @@ edges | dates.js:30:36:30:55 | window.location.hash | dates.js:30:36:30:68 | window. ... ring(1) | provenance | | | dates.js:30:36:30:55 | window.location.hash | dates.js:30:36:30:68 | window. ... ring(1) | provenance | Config | | dates.js:30:36:30:68 | window. ... ring(1) | dates.js:30:17:30:69 | decodeU ... ing(1)) | provenance | | -| dates.js:30:36:30:68 | window. ... ring(1) | dates.js:30:17:30:69 | decodeU ... ing(1)) | provenance | Config | | dates.js:37:42:37:82 | dateFns ... taint) | dates.js:37:31:37:84 | `Time i ... aint)}` | provenance | | -| dates.js:37:42:37:82 | dateFns ... taint) | dates.js:37:31:37:84 | `Time i ... aint)}` | provenance | Config | | dates.js:37:77:37:81 | taint | dates.js:37:42:37:82 | dateFns ... taint) | provenance | | -| dates.js:37:77:37:81 | taint | dates.js:37:42:37:82 | dateFns ... taint) | provenance | Config | | dates.js:38:42:38:82 | luxon.f ... taint) | dates.js:38:31:38:84 | `Time i ... aint)}` | provenance | | -| dates.js:38:42:38:82 | luxon.f ... taint) | dates.js:38:31:38:84 | `Time i ... aint)}` | provenance | Config | | dates.js:38:77:38:81 | taint | dates.js:38:42:38:82 | luxon.f ... taint) | provenance | | -| dates.js:38:77:38:81 | taint | dates.js:38:42:38:82 | luxon.f ... taint) | provenance | Config | | dates.js:39:42:39:84 | moment. ... taint) | dates.js:39:31:39:86 | `Time i ... aint)}` | provenance | | -| dates.js:39:42:39:84 | moment. ... taint) | dates.js:39:31:39:86 | `Time i ... aint)}` | provenance | Config | | dates.js:39:79:39:83 | taint | dates.js:39:42:39:84 | moment. ... taint) | provenance | | -| dates.js:39:79:39:83 | taint | dates.js:39:42:39:84 | moment. ... taint) | provenance | Config | | dates.js:40:42:40:82 | dayjs.f ... taint) | dates.js:40:31:40:84 | `Time i ... aint)}` | provenance | | -| dates.js:40:42:40:82 | dayjs.f ... taint) | dates.js:40:31:40:84 | `Time i ... aint)}` | provenance | Config | | dates.js:40:77:40:81 | taint | dates.js:40:42:40:82 | dayjs.f ... taint) | provenance | | -| dates.js:40:77:40:81 | taint | dates.js:40:42:40:82 | dayjs.f ... taint) | provenance | Config | | dates.js:46:9:46:69 | taint | dates.js:48:83:48:87 | taint | provenance | | | dates.js:46:9:46:69 | taint | dates.js:49:82:49:86 | taint | provenance | | | dates.js:46:9:46:69 | taint | dates.js:50:97:50:101 | taint | provenance | | @@ -767,19 +733,12 @@ edges | dates.js:46:36:46:55 | window.location.hash | dates.js:46:36:46:68 | window. ... ring(1) | provenance | | | dates.js:46:36:46:55 | window.location.hash | dates.js:46:36:46:68 | window. ... ring(1) | provenance | Config | | dates.js:46:36:46:68 | window. ... ring(1) | dates.js:46:17:46:69 | decodeU ... ing(1)) | provenance | | -| dates.js:46:36:46:68 | window. ... ring(1) | dates.js:46:17:46:69 | decodeU ... ing(1)) | provenance | Config | | dates.js:48:42:48:88 | DateTim ... (taint) | dates.js:48:31:48:90 | `Time i ... aint)}` | provenance | | -| dates.js:48:42:48:88 | DateTim ... (taint) | dates.js:48:31:48:90 | `Time i ... aint)}` | provenance | Config | | dates.js:48:83:48:87 | taint | dates.js:48:42:48:88 | DateTim ... (taint) | provenance | | -| dates.js:48:83:48:87 | taint | dates.js:48:42:48:88 | DateTim ... (taint) | provenance | Config | | dates.js:49:42:49:87 | new Dat ... (taint) | dates.js:49:31:49:89 | `Time i ... aint)}` | provenance | | -| dates.js:49:42:49:87 | new Dat ... (taint) | dates.js:49:31:49:89 | `Time i ... aint)}` | provenance | Config | | dates.js:49:82:49:86 | taint | dates.js:49:42:49:87 | new Dat ... (taint) | provenance | | -| dates.js:49:82:49:86 | taint | dates.js:49:42:49:87 | new Dat ... (taint) | provenance | Config | | dates.js:50:42:50:102 | DateTim ... (taint) | dates.js:50:31:50:104 | `Time i ... aint)}` | provenance | | -| dates.js:50:42:50:102 | DateTim ... (taint) | dates.js:50:31:50:104 | `Time i ... aint)}` | provenance | Config | | dates.js:50:97:50:101 | taint | dates.js:50:42:50:102 | DateTim ... (taint) | provenance | | -| dates.js:50:97:50:101 | taint | dates.js:50:42:50:102 | DateTim ... (taint) | provenance | Config | | dates.js:54:9:54:69 | taint | dates.js:57:94:57:98 | taint | provenance | | | dates.js:54:9:54:69 | taint | dates.js:59:80:59:84 | taint | provenance | | | dates.js:54:9:54:69 | taint | dates.js:61:81:61:85 | taint | provenance | | @@ -787,19 +746,12 @@ edges | dates.js:54:36:54:55 | window.location.hash | dates.js:54:36:54:68 | window. ... ring(1) | provenance | | | dates.js:54:36:54:55 | window.location.hash | dates.js:54:36:54:68 | window. ... ring(1) | provenance | Config | | dates.js:54:36:54:68 | window. ... ring(1) | dates.js:54:17:54:69 | decodeU ... ing(1)) | provenance | | -| dates.js:54:36:54:68 | window. ... ring(1) | dates.js:54:17:54:69 | decodeU ... ing(1)) | provenance | Config | | dates.js:57:42:57:99 | moment. ... (taint) | dates.js:57:31:57:101 | `Time i ... aint)}` | provenance | | -| dates.js:57:42:57:99 | moment. ... (taint) | dates.js:57:31:57:101 | `Time i ... aint)}` | provenance | Config | | dates.js:57:94:57:98 | taint | dates.js:57:42:57:99 | moment. ... (taint) | provenance | | -| dates.js:57:94:57:98 | taint | dates.js:57:42:57:99 | moment. ... (taint) | provenance | Config | | dates.js:59:42:59:85 | luxon.e ... (taint) | dates.js:59:31:59:87 | `Time i ... aint)}` | provenance | | -| dates.js:59:42:59:85 | luxon.e ... (taint) | dates.js:59:31:59:87 | `Time i ... aint)}` | provenance | Config | | dates.js:59:80:59:84 | taint | dates.js:59:42:59:85 | luxon.e ... (taint) | provenance | | -| dates.js:59:80:59:84 | taint | dates.js:59:42:59:85 | luxon.e ... (taint) | provenance | Config | | dates.js:61:42:61:86 | dayjs.s ... (taint) | dates.js:61:31:61:88 | `Time i ... aint)}` | provenance | | -| dates.js:61:42:61:86 | dayjs.s ... (taint) | dates.js:61:31:61:88 | `Time i ... aint)}` | provenance | Config | | dates.js:61:81:61:85 | taint | dates.js:61:42:61:86 | dayjs.s ... (taint) | provenance | | -| dates.js:61:81:61:85 | taint | dates.js:61:42:61:86 | dayjs.s ... (taint) | provenance | Config | | dragAndDrop.ts:8:11:8:50 | html | dragAndDrop.ts:15:25:15:28 | html | provenance | | | dragAndDrop.ts:8:18:8:50 | dataTra ... /html') | dragAndDrop.ts:8:11:8:50 | html | provenance | | | dragAndDrop.ts:43:15:43:54 | html | dragAndDrop.ts:50:29:50:32 | html | provenance | | @@ -815,18 +767,12 @@ edges | jquery.js:2:17:2:40 | documen ... .search | jquery.js:2:7:2:40 | tainted | provenance | | | jquery.js:7:20:7:26 | tainted | jquery.js:7:5:7:34 | "
" | provenance | Config | | jquery.js:8:28:8:34 | tainted | jquery.js:8:18:8:34 | "XSS: " + tainted | provenance | | -| jquery.js:8:28:8:34 | tainted | jquery.js:8:18:8:34 | "XSS: " + tainted | provenance | Config | | jquery.js:10:13:10:20 | location | jquery.js:10:13:10:31 | location.toString() | provenance | | -| jquery.js:10:13:10:20 | location | jquery.js:10:13:10:31 | location.toString() | provenance | Config | | jquery.js:10:13:10:31 | location.toString() | jquery.js:10:5:10:40 | "" + ... "" | provenance | Config | | jquery.js:14:38:14:57 | window.location.hash | jquery.js:14:19:14:58 | decodeU ... n.hash) | provenance | | -| jquery.js:14:38:14:57 | window.location.hash | jquery.js:14:19:14:58 | decodeU ... n.hash) | provenance | Config | | jquery.js:15:38:15:59 | window. ... .search | jquery.js:15:19:15:60 | decodeU ... search) | provenance | | -| jquery.js:15:38:15:59 | window. ... .search | jquery.js:15:19:15:60 | decodeU ... search) | provenance | Config | | jquery.js:16:38:16:52 | window.location | jquery.js:16:38:16:63 | window. ... tring() | provenance | | -| jquery.js:16:38:16:52 | window.location | jquery.js:16:38:16:63 | window. ... tring() | provenance | Config | | jquery.js:16:38:16:63 | window. ... tring() | jquery.js:16:19:16:64 | decodeU ... ring()) | provenance | | -| jquery.js:16:38:16:63 | window. ... tring() | jquery.js:16:19:16:64 | decodeU ... ring()) | provenance | Config | | jquery.js:18:7:18:33 | hash | jquery.js:21:5:21:8 | hash | provenance | | | jquery.js:18:7:18:33 | hash | jquery.js:22:5:22:8 | hash | provenance | | | jquery.js:18:7:18:33 | hash | jquery.js:23:5:23:8 | hash | provenance | | @@ -846,10 +792,8 @@ edges | json-stringify.jsx:5:9:5:36 | locale | json-stringify.jsx:19:56:19:61 | locale | provenance | | | json-stringify.jsx:5:9:5:36 | locale | json-stringify.jsx:31:55:31:60 | locale | provenance | | | json-stringify.jsx:5:18:5:36 | req.param("locale") | json-stringify.jsx:5:9:5:36 | locale | provenance | | -| json-stringify.jsx:11:16:11:58 | `https: ... ocale}` | json-stringify.jsx:35:40:35:61 | JSON.st ... jsonLD) | provenance | | -| json-stringify.jsx:11:51:11:56 | locale | json-stringify.jsx:11:16:11:58 | `https: ... ocale}` | provenance | | -| json-stringify.jsx:19:16:19:63 | `https: ... ocale}` | json-stringify.jsx:35:40:35:61 | JSON.st ... jsonLD) | provenance | | -| json-stringify.jsx:19:56:19:61 | locale | json-stringify.jsx:19:16:19:63 | `https: ... ocale}` | provenance | | +| json-stringify.jsx:11:51:11:56 | locale | json-stringify.jsx:35:40:35:61 | JSON.st ... jsonLD) | provenance | | +| json-stringify.jsx:19:56:19:61 | locale | json-stringify.jsx:35:40:35:61 | JSON.st ... jsonLD) | provenance | | | json-stringify.jsx:31:55:31:60 | locale | json-stringify.jsx:31:40:31:61 | JSON.st ... locale) | provenance | | | jwt-server.js:7:9:7:35 | taint | jwt-server.js:9:16:9:20 | taint | provenance | | | jwt-server.js:7:17:7:35 | req.param("wobble") | jwt-server.js:7:9:7:35 | taint | provenance | | @@ -897,19 +841,16 @@ edges | optionalSanitizer.js:45:51:45:56 | target | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | provenance | | | pages/[id].jsx:3:30:3:35 | params [id] | pages/[id].jsx:13:44:13:49 | params [id] | provenance | | | pages/[id].jsx:3:30:3:35 | params [q] | pages/[id].jsx:16:44:16:49 | params [q] | provenance | | -| pages/[id].jsx:5:9:5:14 | { id } | pages/[id].jsx:5:11:5:12 | id | provenance | | +| pages/[id].jsx:5:9:5:14 | { id } | pages/[id].jsx:5:9:5:29 | id | provenance | | | pages/[id].jsx:5:9:5:29 | id | pages/[id].jsx:10:44:10:45 | id | provenance | | -| pages/[id].jsx:5:11:5:12 | id | pages/[id].jsx:5:9:5:29 | id | provenance | | | pages/[id].jsx:5:18:5:29 | router.query | pages/[id].jsx:5:9:5:14 | { id } | provenance | | | pages/[id].jsx:13:44:13:49 | params [id] | pages/[id].jsx:13:44:13:52 | params.id | provenance | | | pages/[id].jsx:16:44:16:49 | params [q] | pages/[id].jsx:16:44:16:51 | params.q | provenance | | | pages/[id].jsx:24:12:27:5 | {\\n ... ,\\n } [id] | pages/[id].jsx:3:30:3:35 | params [id] | provenance | | | pages/[id].jsx:24:12:27:5 | {\\n ... ,\\n } [q] | pages/[id].jsx:3:30:3:35 | params [q] | provenance | | -| pages/[id].jsx:25:11:25:24 | context.params | pages/[id].jsx:25:11:25:27 | context.params.id | provenance | | -| pages/[id].jsx:25:11:25:27 | context.params.id | pages/[id].jsx:25:11:25:33 | context ... d \|\| "" | provenance | | +| pages/[id].jsx:25:11:25:24 | context.params | pages/[id].jsx:25:11:25:33 | context ... d \|\| "" | provenance | | | pages/[id].jsx:25:11:25:33 | context ... d \|\| "" | pages/[id].jsx:24:12:27:5 | {\\n ... ,\\n } [id] | provenance | | -| pages/[id].jsx:26:10:26:22 | context.query | pages/[id].jsx:26:10:26:30 | context ... .foobar | provenance | | -| pages/[id].jsx:26:10:26:30 | context ... .foobar | pages/[id].jsx:26:10:26:36 | context ... r \|\| "" | provenance | | +| pages/[id].jsx:26:10:26:22 | context.query | pages/[id].jsx:26:10:26:36 | context ... r \|\| "" | provenance | | | pages/[id].jsx:26:10:26:36 | context ... r \|\| "" | pages/[id].jsx:24:12:27:5 | {\\n ... ,\\n } [q] | provenance | | | react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted | provenance | | | react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted | provenance | | @@ -925,11 +866,9 @@ edges | 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 | | -| react-use-state.js:4:38:4:48 | window.name | react-use-state.js:4:10:4:14 | state | provenance | | +| react-use-state.js:4:38:4:48 | window.name | react-use-state.js:4:9:4:49 | state | provenance | | | react-use-state.js:9:9:9:43 | state | react-use-state.js:11:51:11:55 | state | provenance | | -| react-use-state.js:9:10:9:14 | state | react-use-state.js:9:9:9:43 | state | provenance | | -| react-use-state.js:10:14:10:24 | window.name | react-use-state.js:9:10:9:14 | state | provenance | | +| react-use-state.js:10:14:10:24 | window.name | react-use-state.js:9:9:9:43 | state | provenance | | | react-use-state.js:15:9:15:43 | state | react-use-state.js:17:51:17:55 | state | provenance | | | react-use-state.js:15:10:15:14 | state | react-use-state.js:15:9:15:43 | state | provenance | | | react-use-state.js:16:20:16:30 | window.name | react-use-state.js:15:10:15:14 | state | provenance | | @@ -956,27 +895,18 @@ edges | sanitiser.js:45:29:45:35 | tainted | sanitiser.js:45:21:45:44 | '' + ... '' | provenance | | | sanitiser.js:48:19:48:25 | tainted | sanitiser.js:48:19:48:46 | tainted ... /g, '') | provenance | | | stored-xss.js:2:39:2:62 | documen ... .search | stored-xss.js:5:20:5:52 | session ... ssion') | provenance | | -| stored-xss.js:2:39:2:62 | documen ... .search | stored-xss.js:5:20:5:52 | session ... ssion') | provenance | Config | | stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:8:20:8:48 | localSt ... local') | provenance | | -| stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:8:20:8:48 | localSt ... local') | provenance | Config | | stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:10:16:10:44 | localSt ... local') | provenance | | -| stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:10:16:10:44 | localSt ... local') | provenance | Config | | stored-xss.js:10:9:10:44 | href | stored-xss.js:12:35:12:38 | href | provenance | | | stored-xss.js:10:16:10:44 | localSt ... local') | stored-xss.js:10:9:10:44 | href | provenance | | | stored-xss.js:12:35:12:38 | href | stored-xss.js:12:20:12:54 | "" | provenance | | | stored-xss.js:12:35:12:38 | href | stored-xss.js:12:20:12:54 | "" | provenance | Config | | string-manipulations.js:5:16:5:37 | documen ... on.href | string-manipulations.js:5:16:5:47 | documen ... lueOf() | provenance | | -| string-manipulations.js:5:16:5:37 | documen ... on.href | string-manipulations.js:5:16:5:47 | documen ... lueOf() | provenance | Config | | string-manipulations.js:6:16:6:37 | documen ... on.href | string-manipulations.js:6:16:6:43 | documen ... f.sup() | provenance | | -| string-manipulations.js:6:16:6:37 | documen ... on.href | string-manipulations.js:6:16:6:43 | documen ... f.sup() | provenance | Config | | string-manipulations.js:7:16:7:37 | documen ... on.href | string-manipulations.js:7:16:7:51 | documen ... rCase() | provenance | | -| string-manipulations.js:7:16:7:37 | documen ... on.href | string-manipulations.js:7:16:7:51 | documen ... rCase() | provenance | Config | | string-manipulations.js:8:16:8:37 | documen ... on.href | string-manipulations.js:8:16:8:48 | documen ... mLeft() | provenance | | -| string-manipulations.js:8:16:8:37 | documen ... on.href | string-manipulations.js:8:16:8:48 | documen ... mLeft() | provenance | Config | | string-manipulations.js:9:36:9:57 | documen ... on.href | string-manipulations.js:9:16:9:58 | String. ... n.href) | provenance | | -| 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:17:3:17 | y | tainted-url-suffix-arguments.js:6:22:6:22 | y | 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 | | @@ -992,7 +922,6 @@ edges | translate.js:7:7:7:61 | searchParams | translate.js:9:27:9:38 | searchParams | provenance | | | translate.js:7:22:7:61 | new URL ... ing(1)) | translate.js:7:7:7:61 | searchParams | provenance | | | translate.js:7:42:7:47 | target | translate.js:7:42:7:60 | target.substring(1) | provenance | | -| translate.js:7:42:7:47 | target | translate.js:7:42:7:60 | target.substring(1) | provenance | Config | | translate.js:7:42:7:60 | target.substring(1) | translate.js:7:22:7:61 | new URL ... ing(1)) | provenance | | | translate.js:9:27:9:38 | searchParams | translate.js:9:27:9:50 | searchP ... 'term') | provenance | Config | | trusted-types-lib.js:1:28:1:28 | x | trusted-types-lib.js:2:12:2:12 | x | provenance | | @@ -1030,7 +959,6 @@ edges | tst.js:20:7:20:61 | searchParams | tst.js:21:18:21:29 | searchParams | provenance | | | tst.js:20:22:20:61 | new URL ... ing(1)) | tst.js:20:7:20:61 | searchParams | provenance | | | tst.js:20:42:20:47 | target | tst.js:20:42:20:60 | target.substring(1) | provenance | | -| tst.js:20:42:20:47 | target | tst.js:20:42:20:60 | target.substring(1) | provenance | Config | | tst.js:20:42:20:60 | target.substring(1) | tst.js:20:22:20:61 | new URL ... ing(1)) | provenance | | | tst.js:21:18:21:29 | searchParams | tst.js:21:18:21:41 | searchP ... 'name') | provenance | Config | | tst.js:24:14:24:19 | target | tst.js:26:18:26:23 | target | provenance | | @@ -1098,19 +1026,14 @@ edges | tst.js:197:9:197:42 | tainted | tst.js:255:23:255:29 | tainted | provenance | | | tst.js:197:19:197:42 | documen ... .search | tst.js:197:9:197:42 | tainted | provenance | | | tst.js:204:35:204:41 | tainted | tst.js:212:28:212:46 | this.state.tainted1 | provenance | | -| tst.js:204:35:204:41 | tainted | tst.js:212:28:212:46 | this.state.tainted1 | provenance | Config | | tst.js:206:46:206:52 | tainted | tst.js:213:28:213:46 | this.state.tainted2 | provenance | | -| tst.js:206:46:206:52 | tainted | tst.js:213:28:213:46 | this.state.tainted2 | provenance | Config | | tst.js:207:38:207:44 | tainted | tst.js:214:28:214:46 | this.state.tainted3 | provenance | | -| tst.js:207:38:207:44 | tainted | tst.js:214:28:214:46 | this.state.tainted3 | provenance | Config | | tst.js:208:35:208:41 | tainted | tst.js:218:32:218:49 | prevState.tainted4 | provenance | | -| tst.js:208:35:208:41 | tainted | tst.js:218:32:218:49 | prevState.tainted4 | provenance | Config | | tst.js:236:35:236:41 | tainted | tst.js:225:28:225:46 | this.props.tainted1 | provenance | | | tst.js:238:20:238:26 | tainted | tst.js:226:28:226:46 | this.props.tainted2 | provenance | | | tst.js:240:23:240:29 | tainted | tst.js:227:28:227:46 | this.props.tainted3 | provenance | | | tst.js:241:23:241:29 | tainted | tst.js:231:32:231:49 | prevProps.tainted4 | provenance | | | tst.js:247:39:247:55 | props.propTainted | tst.js:251:60:251:82 | this.st ... Tainted | provenance | | -| tst.js:247:39:247:55 | props.propTainted | tst.js:251:60:251:82 | this.st ... Tainted | provenance | Config | | tst.js:255:23:255:29 | tainted | tst.js:247:39:247:55 | props.propTainted | provenance | | | tst.js:285:9:285:29 | tainted | tst.js:288:59:288:65 | tainted | provenance | | | tst.js:285:19:285:29 | window.name | tst.js:285:9:285:29 | tainted | provenance | | @@ -1146,17 +1069,13 @@ edges | tst.js:381:7:381:39 | target [taint8] | tst.js:409:18:409:23 | target [taint8] | provenance | | | tst.js:381:16:381:39 | documen ... .search | tst.js:381:7:381:39 | target | provenance | | | tst.js:386:18:386:23 | target | tst.js:386:18:386:29 | target.taint | provenance | | -| tst.js:386:18:386:23 | target | tst.js:386:18:386:29 | target.taint | provenance | Config | | tst.js:391:3:391:8 | [post update] target [taint3] | tst.js:381:7:381:39 | target [taint3] | provenance | | | tst.js:391:19:391:42 | documen ... .search | tst.js:391:3:391:8 | [post update] target [taint3] | provenance | | | tst.js:392:18:392:23 | target [taint3] | tst.js:392:18:392:30 | target.taint3 | provenance | | | tst.js:397:18:397:23 | target | tst.js:397:18:397:30 | target.taint5 | provenance | | -| tst.js:397:18:397:23 | target | tst.js:397:18:397:30 | target.taint5 | provenance | Config | | tst.js:406:18:406:23 | target | tst.js:406:18:406:30 | target.taint7 | provenance | | -| tst.js:406:18:406:23 | target | tst.js:406:18:406:30 | target.taint7 | provenance | Config | | tst.js:408:3:408:8 | [post update] target [taint8] | tst.js:381:7:381:39 | target [taint8] | provenance | | | tst.js:408:19:408:24 | target | tst.js:408:19:408:31 | target.taint8 | provenance | | -| tst.js:408:19:408:24 | target | tst.js:408:19:408:31 | target.taint8 | provenance | Config | | tst.js:408:19:408:24 | target [taint8] | tst.js:408:19:408:31 | target.taint8 | provenance | | | tst.js:408:19:408:31 | target.taint8 | tst.js:408:3:408:8 | [post update] target [taint8] | provenance | | | tst.js:409:18:409:23 | target [taint8] | tst.js:409:18:409:30 | target.taint8 | provenance | | @@ -1166,16 +1085,13 @@ edges | tst.js:416:17:416:46 | window. ... bstr(1) | tst.js:416:7:416:46 | payload | provenance | | | tst.js:419:7:419:55 | match | tst.js:421:20:421:24 | match | provenance | | | tst.js:419:15:419:34 | window.location.hash | tst.js:419:15:419:55 | window. ... (\\w+)/) | provenance | | -| tst.js:419:15:419:34 | window.location.hash | tst.js:419:15:419:55 | window. ... (\\w+)/) | provenance | Config | | tst.js:419:15:419:55 | window. ... (\\w+)/) | tst.js:419:7:419:55 | match | provenance | | | tst.js:421:20:421:24 | match | tst.js:421:20:421:27 | match[1] | provenance | | -| 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('#') [1] | provenance | Config | | tst.js:424:18:424:48 | window. ... it('#') [1] | tst.js:424:18:424:51 | window. ... '#')[1] | provenance | | | 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 | | -| tst.js:430:18:430:23 | target | tst.js:430:18:430:89 | target. ... data>') | provenance | Config | | tst.js:436:6:436:38 | source | tst.js:440:28:440:33 | source | provenance | | | tst.js:436:6:436:38 | source | tst.js:441:33:441:38 | source | provenance | | | tst.js:436:6:436:38 | source | tst.js:442:34:442:39 | source | provenance | | @@ -1187,7 +1103,6 @@ edges | tst.js:453:7:453:39 | source | tst.js:456:36:456:41 | source | provenance | | | tst.js:453:16:453:39 | documen ... .search | tst.js:453:7:453:39 | source | provenance | | | tst.js:456:36:456:41 | source | tst.js:456:18:456:42 | ansiToH ... source) | provenance | | -| tst.js:456:36:456:41 | source | tst.js:456:18:456:42 | ansiToH ... source) | provenance | Config | | tst.js:460:6:460:38 | source | tst.js:463:21:463:26 | source | provenance | | | tst.js:460:6:460:38 | source | tst.js:465:19:465:24 | source | provenance | | | tst.js:460:6:460:38 | source | tst.js:467:20:467:25 | source | provenance | | @@ -1202,12 +1117,10 @@ edges | tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) | provenance | Config | | tst.js:494:18:494:30 | location.hash | tst.js:494:18:494:40 | locatio ... bstr(1) | provenance | Config | | tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) | provenance | | -| tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) | provenance | Config | | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | provenance | | | typeahead.js:20:13:20:45 | target | typeahead.js:21:12:21:17 | target | provenance | | | typeahead.js:20:22:20:45 | documen ... .search | typeahead.js:20:13:20:45 | target | provenance | | | typeahead.js:21:12:21:17 | target | typeahead.js:24:30:24:32 | val | provenance | | -| typeahead.js:21:12:21:17 | target | typeahead.js:24:30:24:32 | val | provenance | Config | | typeahead.js:24:30:24:32 | val | typeahead.js:25:18:25:20 | val | provenance | | | various-concat-obfuscations.js:2:6:2:39 | tainted | various-concat-obfuscations.js:4:14:4:20 | tainted | provenance | | | various-concat-obfuscations.js:2:6:2:39 | tainted | various-concat-obfuscations.js:5:12:5:18 | tainted | provenance | | @@ -1236,9 +1149,7 @@ edges | various-concat-obfuscations.js:12:19:12:25 | tainted | various-concat-obfuscations.js:12:4:12:34 | ["
"] | provenance | Config | | various-concat-obfuscations.js:14:24:14:28 | attrs | various-concat-obfuscations.js:15:28:15:32 | attrs | provenance | | | various-concat-obfuscations.js:15:27:15:55 | (attrs. ... 'left') | various-concat-obfuscations.js:15:10:15:83 | '
' | provenance | Config | -| various-concat-obfuscations.js:15:28:15:32 | attrs | various-concat-obfuscations.js:15:28:15:44 | attrs.defaultattr | provenance | | -| various-concat-obfuscations.js:15:28:15:32 | attrs | various-concat-obfuscations.js:15:28:15:44 | attrs.defaultattr | provenance | Config | -| various-concat-obfuscations.js:15:28:15:44 | attrs.defaultattr | various-concat-obfuscations.js:15:27:15:55 | (attrs. ... 'left') | provenance | | +| various-concat-obfuscations.js:15:28:15:32 | attrs | various-concat-obfuscations.js:15:27:15:55 | (attrs. ... 'left') | provenance | | | various-concat-obfuscations.js:17:24:17:28 | attrs | various-concat-obfuscations.js:18:32:18:36 | attrs | provenance | | | various-concat-obfuscations.js:18:10:18:59 | '
') [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 | | +| various-concat-obfuscations.js:18:32:18:36 | attrs | various-concat-obfuscations.js:18:32:18:58 | attrs.d ... 'left' | provenance | | | various-concat-obfuscations.js:18:32:18:58 | attrs.d ... 'left' | various-concat-obfuscations.js:18:10:18:59 | '
Date: Tue, 17 Sep 2024 15:59:04 +0200 Subject: [PATCH 25/25] JS: Clarify a comment --- .../lib/semmle/javascript/internal/flow_summaries/Arrays.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 e242ed35a67d..9381ca98dd72 100644 --- a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll +++ b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll @@ -487,7 +487,8 @@ class Shift extends SummarizedCallable { input = "Argument[this].ArrayElement[0]" and output = "ReturnValue" or - // ArrayElement[0] is not automatically converted to a taint step, so add it manually + // ArrayElement[0] in the above summary is not automatically converted to a taint step, so manully add + // one from the array to the return value. preservesValue = false and input = "Argument[this]" and output = "ReturnValue"