Skip to content

Commit 9de527f

Browse files
author
Max Schaefer
authored
Merge pull request #49 from asger-semmle/array-map-taint
JavaScript: add taint steps through Array 'join' and 'map' methods
2 parents 8a98e3c + 587e0f9 commit 9de527f

File tree

4 files changed

+32
-1
lines changed

4 files changed

+32
-1
lines changed

change-notes/1.18/analysis-javascript.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
* Modelling of data flow through destructuring assignments has been improved. This may give additional results for the security queries and other queries that rely on data flow.
88

9+
* Modelling of taint flow through the array operations `map` and `join` has been improved. This may give additional results for the security queries.
10+
911
* Support for popular libraries has been improved. Consequently, queries may produce more results on code bases that use the following libraries:
1012
- [bluebird](http://bluebirdjs.com)
1113
- [browserid-crypto](https://github.com/mozilla/browserid-crypto)

javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,13 @@ module TaintTracking {
207207
this = DataFlow::parameterNode(p) and
208208
pred.asExpr() = m.getReceiver()
209209
)
210+
or
211+
// `array.map` with tainted return value in callback
212+
exists (MethodCallExpr m, Function f |
213+
this.asExpr() = m and
214+
m.getMethodName() = "map" and
215+
m.getArgument(0) = f and // Require the argument to be a closure to avoid spurious call/return flow
216+
pred = f.getAReturnedExpr().flow())
210217
)
211218
or
212219
// reading from a tainted object yields a tainted result
@@ -365,7 +372,9 @@ module TaintTracking {
365372
name = "trimRight" or
366373
// sorted, interesting, properties of Object.prototype
367374
name = "toString" or
368-
name = "valueOf"
375+
name = "valueOf" or
376+
// sorted, interesting, properties of Array.prototype
377+
name = "join"
369378
) or
370379
exists (int i | pred.asExpr() = astNode.(MethodCallExpr).getArgument(i) |
371380
name = "concat" or

javascript/ql/test/query-tests/Security/CWE-022/TaintedPath.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
| TaintedPath.js:85:31:85:74 | require ... ).query | This path depends on $@. | TaintedPath.js:85:61:85:67 | req.url | a user-provided value |
2222
| TaintedPath.js:86:31:86:73 | require ... ).query | This path depends on $@. | TaintedPath.js:86:60:86:66 | req.url | a user-provided value |
2323
| TaintedPath.js:94:48:94:60 | req.params[0] | This path depends on $@. | TaintedPath.js:94:48:94:60 | req.params[0] | a user-provided value |
24+
| tainted-array-steps.js:11:29:11:54 | ['publi ... in('/') | This path depends on $@. | tainted-array-steps.js:9:24:9:30 | req.url | a user-provided value |
25+
| tainted-array-steps.js:15:29:15:43 | parts.join('/') | This path depends on $@. | tainted-array-steps.js:9:24:9:30 | req.url | a user-provided value |
2426
| tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value |
2527
| tainted-sendFile.js:7:16:7:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:7:16:7:33 | req.param("gimme") | a user-provided value |
2628
| views.js:1:43:1:55 | req.params[0] | This path depends on $@. | views.js:1:43:1:55 | req.params[0] | a user-provided value |
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
var fs = require('fs'),
2+
http = require('http'),
3+
url = require('url'),
4+
sanitize = require('sanitize-filename'),
5+
pathModule = require('path')
6+
;
7+
8+
var server = http.createServer(function(req, res) {
9+
let path = url.parse(req.url, true).query.path;
10+
// BAD: taint is preserved
11+
res.write(fs.readFileSync(['public', path].join('/')));
12+
// BAD: taint is preserved
13+
let parts = ['public', path];
14+
parts = parts.map(x => x.toLowerCase());
15+
res.write(fs.readFileSync(parts.join('/')));
16+
});
17+
18+
server.listen();

0 commit comments

Comments
 (0)