Skip to content

Commit cf94c93

Browse files
authored
Merge pull request #8481 from erik-krogh/schemeChain
JS: recognize string replacement chains as scheme checks in js/incomplete-url-scheme-check
2 parents e12b6df + 693c77f commit cf94c93

File tree

3 files changed

+46
-0
lines changed

3 files changed

+46
-0
lines changed

javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515

1616
import javascript
17+
import semmle.javascript.security.IncompleteBlacklistSanitizer as IncompleteBlacklistSanitizer
1718

1819
/** A URL scheme that can be used to represent executable code. */
1920
class DangerousScheme extends string {
@@ -55,6 +56,21 @@ DataFlow::SourceNode schemeOf(DataFlow::Node url) {
5556
)
5657
}
5758

59+
/**
60+
* A chain of replace calls that replaces one or more dangerous schemes.
61+
*/
62+
class SchemeReplacementChain extends IncompleteBlacklistSanitizer::StringReplaceCallSequence {
63+
SchemeReplacementChain() { this.getAMember().getAReplacedString() instanceof DangerousScheme }
64+
65+
/**
66+
* Gets the source node that the replacement happens on.
67+
* The result is the receiver of the first call in the chain.
68+
*/
69+
DataFlow::Node getReplacementSource() {
70+
result = this.getReceiver+() and not result instanceof DataFlow::MethodCallNode
71+
}
72+
}
73+
5874
/** Gets a data-flow node that checks `nd` against the given `scheme`. */
5975
DataFlow::Node schemeCheck(DataFlow::Node nd, DangerousScheme scheme) {
6076
// check of the form `nd.startsWith(scheme)`
@@ -73,6 +89,11 @@ DataFlow::Node schemeCheck(DataFlow::Node nd, DangerousScheme scheme) {
7389
schemeOf(nd).flowsTo(candidate)
7490
)
7591
or
92+
exists(SchemeReplacementChain chain | result = chain |
93+
scheme = chain.getAMember().getAReplacedString() and
94+
nd = chain.getReplacementSource()
95+
)
96+
or
7697
// propagate through trimming, case conversion, and regexp replace
7798
exists(DataFlow::MethodCallNode stringop |
7899
stringop.getMethodName().matches("trim%") or

javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@
1111
| IncompleteUrlSchemeCheck.js:87:7:87:40 | /^(java ... scheme) | This check does not consider vbscript:. |
1212
| IncompleteUrlSchemeCheck.js:94:10:94:15 | scheme | This check does not consider vbscript:. |
1313
| IncompleteUrlSchemeCheck.js:104:6:104:39 | /^(java ... scheme) | This check does not consider vbscript:. |
14+
| IncompleteUrlSchemeCheck.js:110:12:112:29 | url // ... :/, "") | This check does not consider vbscript:. |
15+
| IncompleteUrlSchemeCheck.js:124:11:124:34 | url.rep ... :/, "") | This check does not consider vbscript:. |

javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,26 @@ function test14(url) {
105105
return "about:blank";
106106
return url;
107107
}
108+
109+
function chain1(url) {
110+
return url // NOT OK
111+
.replace(/javascript:/, "")
112+
.replace(/data:/, "");
113+
}
114+
115+
function chain2(url) {
116+
return url // OK
117+
.replace(/javascript:/, "")
118+
.replace(/data:/, "")
119+
.replace(/vbscript:/, "");
120+
}
121+
122+
function chain3(url) {
123+
url = url.replace(/javascript:/, "")
124+
url = url.replace(/data:/, ""); // NOT OK
125+
return url;
126+
}
127+
128+
function chain4(url) {
129+
return url.replace(/(javascript|data):/, ""); // NOT OK - but not flagged [INCONSISTENCY]
130+
}

0 commit comments

Comments
 (0)