Skip to content

Commit 0e4e0f4

Browse files
committed
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.
1 parent 74ab346 commit 0e4e0f4

File tree

3 files changed

+15
-8
lines changed

3 files changed

+15
-8
lines changed

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,13 @@ class StringSplitHashOrQuestionMark extends SummarizedCallable {
8888
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
8989
preservesValue = false and
9090
(
91-
input = "Argument[this].OptionalBarrier[tainted-url-suffix]" and
91+
input = "Argument[this].OptionalBarrier[split-url-suffix]" and
9292
output = "ReturnValue.ArrayElement"
9393
or
94-
input = "Argument[this].OptionalStep[tainted-url-suffix]" and
94+
input = "Argument[this].OptionalStep[split-url-suffix-pre]" and
95+
output = "ReturnValue.ArrayElement[0]"
96+
or
97+
input = "Argument[this].OptionalStep[split-url-suffix-post]" and
9598
output = "ReturnValue.ArrayElement[1]" // TODO: support ArrayElement[1..]
9699
)
97100
}

javascript/ql/lib/semmle/javascript/security/TaintedUrlSuffix.qll

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ module TaintedUrlSuffix {
4444
*/
4545
predicate isBarrier(Node node, FlowLabel label) {
4646
label = label() and
47-
DataFlowPrivate::optionalBarrier(node, "tainted-url-suffix")
47+
DataFlowPrivate::optionalBarrier(node, "split-url-suffix")
4848
}
4949

5050
/**
@@ -55,7 +55,11 @@ module TaintedUrlSuffix {
5555
predicate step(Node src, Node dst, FlowLabel srclbl, FlowLabel dstlbl) {
5656
srclbl = label() and
5757
dstlbl.isTaint() and
58-
DataFlowPrivate::optionalStep(src, "tainted-url-suffix", dst)
58+
DataFlowPrivate::optionalStep(src, "split-url-suffix-post", dst)
59+
or
60+
srclbl = label() and
61+
dstlbl = label() and
62+
DataFlowPrivate::optionalStep(src, "split-url-suffix-pre", dst)
5963
or
6064
// Transition from URL suffix to full taint when extracting the query/fragment part.
6165
srclbl = label() and

javascript/ql/test/library-tests/TaintedUrlSuffix/tst.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ function t1() {
55

66
sink(href); // $ flow=tainted-url-suffix
77

8-
sink(href.split('#')[0]); // $ MISSING: flow=tainted-url-suffix
8+
sink(href.split('#')[0]); // $ flow=tainted-url-suffix
99
sink(href.split('#')[1]); // $ flow=taint
10-
sink(href.split('#').pop()); // $ flow=taint
10+
sink(href.split('#').pop()); // $ flow=taint flow=tainted-url-suffix
1111
sink(href.split('#')[2]); // $ MISSING: flow=taint // currently the split() summary only propagates to index 1
1212

13-
sink(href.split('?')[0]); // $ MISSING: flow=tainted-url-suffix
13+
sink(href.split('?')[0]); // $ flow=tainted-url-suffix
1414
sink(href.split('?')[1]); // $ flow=taint
15-
sink(href.split('?').pop()); // $ flow=taint
15+
sink(href.split('?').pop()); // $ flow=taint flow=tainted-url-suffix
1616
sink(href.split('?')[2]); // $ MISSING: flow=taint
1717

1818
sink(href.split(blah())[0]); // $ flow=tainted-url-suffix

0 commit comments

Comments
 (0)