Skip to content

Commit 608094f

Browse files
committed
JS: track taint through serialize-javascript calls with object arguments
1 parent a96ea18 commit 608094f

File tree

3 files changed

+42
-4
lines changed

3 files changed

+42
-4
lines changed

javascript/ql/lib/semmle/javascript/security/dataflow/Xss.qll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,20 @@ module Shared {
5858
}
5959
}
6060

61+
/**
62+
* Additional flow step to track taint through `serialize-javascript` calls with object arguments.
63+
*/
64+
private class SerializeJavascriptFlowStep extends DataFlow::AdditionalFlowStep {
65+
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
66+
exists(DataFlow::CallNode call, DataFlow::PropWrite propWrite |
67+
call = DataFlow::moduleImport("serialize-javascript").getACall() and
68+
succ = call and
69+
propWrite.getRhs() = pred and
70+
propWrite.getBase().getALocalSource().flowsTo(call.getArgument(0))
71+
)
72+
}
73+
}
74+
6175
/**
6276
* A call to `serialize-javascript`, which prevents XSS vulnerabilities unless
6377
* the `unsafe` option is set to `true`.

javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@
7070
| tst2.js:76:12:76:18 | other.p | tst2.js:69:9:69:9 | p | tst2.js:76:12:76:18 | other.p | Cross-site scripting vulnerability due to a $@. | tst2.js:69:9:69:9 | p | user-provided value |
7171
| tst2.js:88:12:88:12 | p | tst2.js:82:9:82:9 | p | tst2.js:88:12:88:12 | p | Cross-site scripting vulnerability due to a $@. | tst2.js:82:9:82:9 | p | user-provided value |
7272
| tst2.js:89:12:89:18 | other.p | tst2.js:82:9:82:9 | p | tst2.js:89:12:89:18 | other.p | Cross-site scripting vulnerability due to a $@. | tst2.js:82:9:82:9 | p | user-provided value |
73+
| tst2.js:101:12:101:17 | unsafe | tst2.js:93:9:93:9 | p | tst2.js:101:12:101:17 | unsafe | Cross-site scripting vulnerability due to a $@. | tst2.js:93:9:93:9 | p | user-provided value |
74+
| tst2.js:113:12:113:17 | unsafe | tst2.js:105:9:105:9 | p | tst2.js:113:12:113:17 | unsafe | Cross-site scripting vulnerability due to a $@. | tst2.js:105:9:105:9 | p | user-provided value |
7375
| tst3.js:6:12:6:12 | p | tst3.js:5:9:5:9 | p | tst3.js:6:12:6:12 | p | Cross-site scripting vulnerability due to a $@. | tst3.js:5:9:5:9 | p | user-provided value |
7476
| tst3.js:12:12:12:15 | code | tst3.js:11:32:11:39 | reg.body | tst3.js:12:12:12:15 | code | Cross-site scripting vulnerability due to a $@. | tst3.js:11:32:11:39 | reg.body | user-provided value |
7577
edges
@@ -239,6 +241,16 @@ edges
239241
| tst2.js:86:15:86:27 | sortKeys(obj) [p] | tst2.js:86:7:86:27 | other [p] | provenance | |
240242
| tst2.js:86:24:86:26 | obj [p] | tst2.js:86:15:86:27 | sortKeys(obj) [p] | provenance | |
241243
| tst2.js:89:12:89:16 | other [p] | tst2.js:89:12:89:18 | other.p | provenance | |
244+
| tst2.js:93:7:93:24 | p | tst2.js:99:51:99:51 | p | provenance | |
245+
| tst2.js:93:9:93:9 | p | tst2.js:93:7:93:24 | p | provenance | |
246+
| tst2.js:99:7:99:69 | unsafe | tst2.js:101:12:101:17 | unsafe | provenance | |
247+
| tst2.js:99:16:99:69 | seriali ... true}) | tst2.js:99:7:99:69 | unsafe | provenance | |
248+
| tst2.js:99:51:99:51 | p | tst2.js:99:16:99:69 | seriali ... true}) | provenance | |
249+
| tst2.js:105:7:105:24 | p | tst2.js:110:28:110:28 | p | provenance | |
250+
| tst2.js:105:9:105:9 | p | tst2.js:105:7:105:24 | p | provenance | |
251+
| tst2.js:110:28:110:28 | p | tst2.js:111:16:111:55 | seriali ... true}) | provenance | |
252+
| tst2.js:111:7:111:55 | unsafe | tst2.js:113:12:113:17 | unsafe | provenance | |
253+
| tst2.js:111:16:111:55 | seriali ... true}) | tst2.js:111:7:111:55 | unsafe | provenance | |
242254
| tst3.js:5:7:5:24 | p | tst3.js:6:12:6:12 | p | provenance | |
243255
| tst3.js:5:9:5:9 | p | tst3.js:5:7:5:24 | p | provenance | |
244256
| tst3.js:11:9:11:74 | code | tst3.js:12:12:12:15 | code | provenance | |
@@ -457,6 +469,18 @@ nodes
457469
| tst2.js:88:12:88:12 | p | semmle.label | p |
458470
| tst2.js:89:12:89:16 | other [p] | semmle.label | other [p] |
459471
| tst2.js:89:12:89:18 | other.p | semmle.label | other.p |
472+
| tst2.js:93:7:93:24 | p | semmle.label | p |
473+
| tst2.js:93:9:93:9 | p | semmle.label | p |
474+
| tst2.js:99:7:99:69 | unsafe | semmle.label | unsafe |
475+
| tst2.js:99:16:99:69 | seriali ... true}) | semmle.label | seriali ... true}) |
476+
| tst2.js:99:51:99:51 | p | semmle.label | p |
477+
| tst2.js:101:12:101:17 | unsafe | semmle.label | unsafe |
478+
| tst2.js:105:7:105:24 | p | semmle.label | p |
479+
| tst2.js:105:9:105:9 | p | semmle.label | p |
480+
| tst2.js:110:28:110:28 | p | semmle.label | p |
481+
| tst2.js:111:7:111:55 | unsafe | semmle.label | unsafe |
482+
| tst2.js:111:16:111:55 | seriali ... true}) | semmle.label | seriali ... true}) |
483+
| tst2.js:113:12:113:17 | unsafe | semmle.label | unsafe |
460484
| tst3.js:5:7:5:24 | p | semmle.label | p |
461485
| tst3.js:5:9:5:9 | p | semmle.label | p |
462486
| tst3.js:6:12:6:12 | p | semmle.label | p |

javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/tst2.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,25 +90,25 @@ app.get('/baz', function(req, res) {
9090
});
9191

9292
app.get('/baz', function(req, res) {
93-
let { p } = req.params; // $ MISSING: Source
93+
let { p } = req.params; // $ Source
9494

9595
var serialized = serializeJavaScript(p);
9696

9797
res.send(serialized);
9898

9999
var unsafe = serializeJavaScript({someProperty: p}, {unsafe: true});
100100

101-
res.send(unsafe); // $ MISSING: Alert
101+
res.send(unsafe); // $ Alert
102102
});
103103

104104
app.get('/baz', function(req, res) {
105-
let { p } = req.params; // $ MISSING: Source
105+
let { p } = req.params; // $ Source
106106

107107
var serialized = serializeJavaScript(p);
108108

109109
res.send(serialized);
110110
let obj = {someProperty: p};
111111
var unsafe = serializeJavaScript(obj, {unsafe: true});
112112

113-
res.send(unsafe); // $ MISSING: Alert
113+
res.send(unsafe); // $ Alert
114114
});

0 commit comments

Comments
 (0)