Skip to content

Commit 193ddfc

Browse files
committed
add taint through the qs library
1 parent e0a123c commit 193ddfc

File tree

4 files changed

+127
-0
lines changed

4 files changed

+127
-0
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
lgtm,codescanning
2+
* The security queries now track taint through more query string parsers.
3+
Affected packages are
4+
[qs](https://npmjs.com/package/qs)

javascript/ql/src/semmle/javascript/frameworks/UriLibraries.qll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,20 @@ module querystring {
292292
}
293293
}
294294

295+
/**
296+
* A taint step through a call to [qs](https://npmjs.com/package/qs)
297+
*/
298+
private class QsStep extends TaintTracking::SharedTaintStep {
299+
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
300+
exists(API::CallNode call |
301+
call = API::moduleImport("qs").getMember(["parse", "stringify"]).getACall()
302+
|
303+
pred = call.getArgument(0) and
304+
succ = call
305+
)
306+
}
307+
}
308+
295309
/**
296310
* Provides steps for the `goog.Uri` class in the closure library.
297311
*/

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

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,6 +1285,44 @@ nodes
12851285
| TaintedPath.js:195:50:195:53 | path |
12861286
| TaintedPath.js:195:50:195:53 | path |
12871287
| TaintedPath.js:195:50:195:53 | path |
1288+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
1289+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
1290+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
1291+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
1292+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
1293+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
1294+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
1295+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
1296+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
1297+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
1298+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
1299+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
1300+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
1301+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
1302+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
1303+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
1304+
| TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
1305+
| TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
1306+
| TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
1307+
| TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
1308+
| TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
1309+
| TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
1310+
| TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
1311+
| TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
1312+
| TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
1313+
| TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
1314+
| TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
1315+
| TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
1316+
| TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
1317+
| TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
1318+
| TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
1319+
| TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
1320+
| TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
1321+
| TaintedPath.js:201:38:201:44 | req.url |
1322+
| TaintedPath.js:201:38:201:44 | req.url |
1323+
| TaintedPath.js:201:38:201:44 | req.url |
1324+
| TaintedPath.js:201:38:201:44 | req.url |
1325+
| TaintedPath.js:201:38:201:44 | req.url |
12881326
| normalizedPaths.js:11:7:11:27 | path |
12891327
| normalizedPaths.js:11:7:11:27 | path |
12901328
| normalizedPaths.js:11:7:11:27 | path |
@@ -5506,6 +5544,70 @@ edges
55065544
| TaintedPath.js:195:50:195:53 | path | TaintedPath.js:195:29:195:54 | pathMod ... e(path) |
55075545
| TaintedPath.js:195:50:195:53 | path | TaintedPath.js:195:29:195:54 | pathMod ... e(path) |
55085546
| TaintedPath.js:195:50:195:53 | path | TaintedPath.js:195:29:195:54 | pathMod ... e(path) |
5547+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5548+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5549+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5550+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5551+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5552+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5553+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5554+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5555+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5556+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5557+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5558+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5559+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5560+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5561+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5562+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5563+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5564+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5565+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5566+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5567+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5568+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5569+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5570+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5571+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5572+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5573+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5574+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5575+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5576+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5577+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5578+
| TaintedPath.js:201:29:201:45 | qs.parse(req.url) | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo |
5579+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5580+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5581+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5582+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5583+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5584+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5585+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5586+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5587+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5588+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5589+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5590+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5591+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5592+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5593+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5594+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5595+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5596+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5597+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5598+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5599+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5600+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5601+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5602+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5603+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5604+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5605+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5606+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5607+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5608+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5609+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
5610+
| TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:45 | qs.parse(req.url) |
55095611
| normalizedPaths.js:11:7:11:27 | path | normalizedPaths.js:13:19:13:22 | path |
55105612
| normalizedPaths.js:11:7:11:27 | path | normalizedPaths.js:13:19:13:22 | path |
55115613
| normalizedPaths.js:11:7:11:27 | path | normalizedPaths.js:13:19:13:22 | path |
@@ -8627,6 +8729,7 @@ edges
86278729
| TaintedPath.js:179:29:179:57 | path.re ... /g, '') | TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:179:29:179:57 | path.re ... /g, '') | This path depends on $@. | TaintedPath.js:166:24:166:30 | req.url | a user-provided value |
86288730
| TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | This path depends on $@. | TaintedPath.js:166:24:166:30 | req.url | a user-provided value |
86298731
| TaintedPath.js:195:29:195:84 | pathMod ... +/, '') | TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:195:29:195:84 | pathMod ... +/, '') | This path depends on $@. | TaintedPath.js:166:24:166:30 | req.url | a user-provided value |
8732+
| TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo | TaintedPath.js:201:38:201:44 | req.url | TaintedPath.js:201:29:201:49 | qs.pars ... rl).foo | This path depends on $@. | TaintedPath.js:201:38:201:44 | req.url | a user-provided value |
86308733
| normalizedPaths.js:13:19:13:22 | path | normalizedPaths.js:11:14:11:27 | req.query.path | normalizedPaths.js:13:19:13:22 | path | This path depends on $@. | normalizedPaths.js:11:14:11:27 | req.query.path | a user-provided value |
86318734
| normalizedPaths.js:14:19:14:29 | './' + path | normalizedPaths.js:11:14:11:27 | req.query.path | normalizedPaths.js:14:19:14:29 | './' + path | This path depends on $@. | normalizedPaths.js:11:14:11:27 | req.query.path | a user-provided value |
86328735
| normalizedPaths.js:15:19:15:38 | path + '/index.html' | normalizedPaths.js:11:14:11:27 | req.query.path | normalizedPaths.js:15:19:15:38 | path + '/index.html' | This path depends on $@. | normalizedPaths.js:11:14:11:27 | req.query.path | a user-provided value |

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,4 +193,10 @@ var server = http.createServer(function(req, res) {
193193

194194
res.write(fs.readFileSync("prefix" + path.replace(/^(\.\.[\/\\])+/, ''))); // NOT OK - not normalized
195195
res.write(fs.readFileSync(pathModule.normalize(path).replace(/^(\.\.[\/\\])+/, ''))); // NOT OK (can be absolute)
196+
});
197+
198+
var server = http.createServer(function(req, res) {
199+
// tests for a few more uri-libraries
200+
const qs = require("qs");
201+
res.write(fs.readFileSync(qs.parse(req.url).foo)); // NOT OK
196202
});

0 commit comments

Comments
 (0)