Skip to content

Commit 3b34cd7

Browse files
committed
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().
1 parent 24983a5 commit 3b34cd7

File tree

1 file changed

+33
-1
lines changed
  • javascript/ql/lib/semmle/javascript/internal/flow_summaries

1 file changed

+33
-1
lines changed

javascript/ql/lib/semmle/javascript/internal/flow_summaries/Strings.qll

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ class StringSplit extends SummarizedCallable {
5555
StringSplit() { this = "String#split" }
5656

5757
override DataFlow::MethodCallNode getACallSimple() {
58-
result.getMethodName() = "split" and result.getNumArgument() = 1
58+
result.getMethodName() = "split" and
59+
result.getNumArgument() = [1, 2] and
60+
not result.getArgument(0).getStringValue() = ["#", "?"]
5961
}
6062

6163
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
@@ -64,3 +66,33 @@ class StringSplit extends SummarizedCallable {
6466
output = "ReturnValue.ArrayElement"
6567
}
6668
}
69+
70+
/**
71+
* A call of form `x.split("#")` or `x.split("?")`.
72+
*
73+
* These are of special significance when tracking a tainted URL suffix, such as `window.location.href`,
74+
* because the first element of the resulting array should not be considered tainted.
75+
*
76+
* This summary defaults to the same behaviour as the general `.split()` case, but it contains optional steps
77+
* and barriers named `tainted-url-suffix` that should be activated when tracking a tainted URL suffix.
78+
*/
79+
class StringSplitHashOrQuestionMark extends SummarizedCallable {
80+
StringSplitHashOrQuestionMark() { this = "String#split with '#' or '?'" }
81+
82+
override DataFlow::MethodCallNode getACallSimple() {
83+
result.getMethodName() = "split" and
84+
result.getNumArgument() = [1, 2] and
85+
result.getArgument(0).getStringValue() = ["#", "?"]
86+
}
87+
88+
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
89+
preservesValue = false and
90+
(
91+
input = "Argument[this].OptionalBarrier[tainted-url-suffix]" and
92+
output = "ReturnValue.ArrayElement"
93+
or
94+
input = "Argument[this].OptionalStep[tainted-url-suffix]" and
95+
output = "ReturnValue.ArrayElement[1]" // TODO: support ArrayElement[1..]
96+
)
97+
}
98+
}

0 commit comments

Comments
 (0)