Skip to content

Commit a42480d

Browse files
authored
Merge pull request github#18733 from asgerf/js/query-string-parse-fn
JS: Model query-string parsers that strip off a leading '#' or '?'
2 parents be0b3ba + 4524297 commit a42480d

File tree

3 files changed

+36
-0
lines changed

3 files changed

+36
-0
lines changed

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,18 @@ module TaintedUrlSuffix {
141141
// If the regexp is unknown, assume it will extract the URL suffix
142142
not exists(re.getRoot())
143143
)
144+
or
145+
// Query-string parsers that strip off a leading '#' or '?'.
146+
state1.isTaintedUrlSuffix() and
147+
state2.isTaint() and
148+
exists(DataFlow::CallNode call |
149+
node1 = call.getArgument(0) and
150+
node2 = call
151+
|
152+
call = API::moduleImport("query-string").getMember(["parse", "extract"]).getACall()
153+
or
154+
call = API::moduleImport("querystringify").getMember("parse").getACall()
155+
)
144156
)
145157
}
146158

javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,14 @@ nodes
147147
| tst15.js:15:23:15:28 | search | semmle.label | search |
148148
| tst15.js:15:23:15:66 | search. ... ', 10)) | semmle.label | search. ... ', 10)) |
149149
| tst15.js:15:23:15:79 | search. ... ring(1) | semmle.label | search. ... ring(1) |
150+
| tst16.js:5:21:5:54 | querySt ... search) | semmle.label | querySt ... search) |
151+
| tst16.js:5:21:5:59 | querySt ... h).data | semmle.label | querySt ... h).data |
152+
| tst16.js:5:39:5:53 | location.search | semmle.label | location.search |
153+
| tst16.js:6:21:6:56 | querySt ... search) | semmle.label | querySt ... search) |
154+
| tst16.js:6:41:6:55 | location.search | semmle.label | location.search |
155+
| tst16.js:7:21:7:57 | queryst ... search) | semmle.label | queryst ... search) |
156+
| tst16.js:7:21:7:62 | queryst ... h).data | semmle.label | queryst ... h).data |
157+
| tst16.js:7:42:7:56 | location.search | semmle.label | location.search |
150158
| tst.js:2:19:2:69 | /.*redi ... n.href) | semmle.label | /.*redi ... n.href) |
151159
| tst.js:2:19:2:72 | /.*redi ... ref)[1] | semmle.label | /.*redi ... ref)[1] |
152160
| tst.js:2:47:2:68 | documen ... on.href | semmle.label | documen ... on.href |
@@ -303,6 +311,11 @@ edges
303311
| tst15.js:14:23:14:45 | search. ... (0, 10) | tst15.js:14:23:14:58 | search. ... ring(1) | provenance | Config |
304312
| tst15.js:15:23:15:28 | search | tst15.js:15:23:15:66 | search. ... ', 10)) | provenance | |
305313
| tst15.js:15:23:15:66 | search. ... ', 10)) | tst15.js:15:23:15:79 | search. ... ring(1) | provenance | Config |
314+
| tst16.js:5:21:5:54 | querySt ... search) | tst16.js:5:21:5:59 | querySt ... h).data | provenance | |
315+
| tst16.js:5:39:5:53 | location.search | tst16.js:5:21:5:54 | querySt ... search) | provenance | Config |
316+
| tst16.js:6:41:6:55 | location.search | tst16.js:6:21:6:56 | querySt ... search) | provenance | Config |
317+
| tst16.js:7:21:7:57 | queryst ... search) | tst16.js:7:21:7:62 | queryst ... h).data | provenance | |
318+
| tst16.js:7:42:7:56 | location.search | tst16.js:7:21:7:57 | queryst ... search) | provenance | Config |
306319
| tst.js:2:19:2:69 | /.*redi ... n.href) | tst.js:2:19:2:72 | /.*redi ... ref)[1] | provenance | |
307320
| tst.js:2:47:2:68 | documen ... on.href | tst.js:2:19:2:69 | /.*redi ... n.href) | provenance | Config |
308321
| tst.js:6:20:6:56 | indirec ... n.href) | tst.js:6:20:6:59 | indirec ... ref)[1] | provenance | |
@@ -392,6 +405,9 @@ subpaths
392405
| tst15.js:13:23:13:54 | search. ... ring(1) | tst15.js:12:18:12:41 | documen ... .search | tst15.js:13:23:13:54 | search. ... ring(1) | Untrusted URL redirection depends on a $@. | tst15.js:12:18:12:41 | documen ... .search | user-provided value |
393406
| tst15.js:14:23:14:58 | search. ... ring(1) | tst15.js:12:18:12:41 | documen ... .search | tst15.js:14:23:14:58 | search. ... ring(1) | Untrusted URL redirection depends on a $@. | tst15.js:12:18:12:41 | documen ... .search | user-provided value |
394407
| tst15.js:15:23:15:79 | search. ... ring(1) | tst15.js:12:18:12:41 | documen ... .search | tst15.js:15:23:15:79 | search. ... ring(1) | Untrusted URL redirection depends on a $@. | tst15.js:12:18:12:41 | documen ... .search | user-provided value |
408+
| tst16.js:5:21:5:59 | querySt ... h).data | tst16.js:5:39:5:53 | location.search | tst16.js:5:21:5:59 | querySt ... h).data | Untrusted URL redirection depends on a $@. | tst16.js:5:39:5:53 | location.search | user-provided value |
409+
| tst16.js:6:21:6:56 | querySt ... search) | tst16.js:6:41:6:55 | location.search | tst16.js:6:21:6:56 | querySt ... search) | Untrusted URL redirection depends on a $@. | tst16.js:6:41:6:55 | location.search | user-provided value |
410+
| tst16.js:7:21:7:62 | queryst ... h).data | tst16.js:7:42:7:56 | location.search | tst16.js:7:21:7:62 | queryst ... h).data | Untrusted URL redirection depends on a $@. | tst16.js:7:42:7:56 | location.search | user-provided value |
395411
| tst.js:2:19:2:72 | /.*redi ... ref)[1] | tst.js:2:47:2:68 | documen ... on.href | tst.js:2:19:2:72 | /.*redi ... ref)[1] | Untrusted URL redirection depends on a $@. | tst.js:2:47:2:68 | documen ... on.href | user-provided value |
396412
| tst.js:6:20:6:59 | indirec ... ref)[1] | tst.js:6:34:6:55 | documen ... on.href | tst.js:6:20:6:59 | indirec ... ref)[1] | Untrusted URL redirection depends on a $@. | tst.js:6:34:6:55 | documen ... on.href | user-provided value |
397413
| tst.js:10:19:10:84 | new Reg ... ref)[1] | tst.js:10:59:10:80 | documen ... on.href | tst.js:10:19:10:84 | new Reg ... ref)[1] | Untrusted URL redirection depends on a $@. | tst.js:10:59:10:80 | documen ... on.href | user-provided value |
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import queryString from 'query-string';
2+
import querystringify from 'querystringify';
3+
4+
function foo() {
5+
location.href = queryString.parse(location.search).data; // NOT OK
6+
location.href = queryString.extract(location.search); // NOT OK
7+
location.href = querystringify.parse(location.search).data; // NOT OK
8+
}

0 commit comments

Comments
 (0)