Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a5c221f

Browse files
committed
JS: Port PrototypePollutingMergeCall
1 parent adf7d54 commit a5c221f

3 files changed

Lines changed: 88 additions & 64 deletions

File tree

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

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,56 @@ import semmle.javascript.dependencies.SemVer
1414
import PrototypePollutionCustomizations::PrototypePollution
1515

1616
// Materialize flow labels
17-
private class ConcreteTaintedObjectWrapper extends TaintedObjectWrapper {
17+
/**
18+
* We no longer use this flow label, since it does not work in a world where flow states inherit taint steps.
19+
*/
20+
deprecated private class ConcreteTaintedObjectWrapper extends TaintedObjectWrapper {
1821
ConcreteTaintedObjectWrapper() { this = this }
1922
}
2023

2124
/**
2225
* A taint tracking configuration for user-controlled objects flowing into deep `extend` calls,
2326
* leading to prototype pollution.
2427
*/
25-
class Configuration extends TaintTracking::Configuration {
28+
module PrototypePollutionConfig implements DataFlow::StateConfigSig {
29+
class FlowState = DataFlow::FlowLabel;
30+
31+
predicate isSource(DataFlow::Node node, DataFlow::FlowLabel label) {
32+
node.(Source).getAFlowLabel() = label
33+
}
34+
35+
predicate isSink(DataFlow::Node node, DataFlow::FlowLabel label) {
36+
node.(Sink).getAFlowLabel() = label
37+
}
38+
39+
predicate isAdditionalFlowStep(
40+
DataFlow::Node src, DataFlow::FlowLabel inlbl, DataFlow::Node dst, DataFlow::FlowLabel outlbl
41+
) {
42+
TaintedObject::step(src, dst, inlbl, outlbl)
43+
}
44+
45+
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet contents) {
46+
// For recursive merge sinks, the deeply tainted object only needs to be reachable from the input, the input itself
47+
// does not need to be deeply tainted.
48+
isSink(node, TaintedObject::label()) and
49+
contents = DataFlow::ContentSet::anyProperty()
50+
}
51+
52+
predicate isBarrier(DataFlow::Node node, DataFlow::FlowLabel label) {
53+
node = TaintedObject::SanitizerGuard::getABarrierNode(label)
54+
}
55+
}
56+
57+
/**
58+
* Taint tracking for user-controlled objects flowing into deep `extend` calls,
59+
* leading to prototype pollution.
60+
*/
61+
module PrototypePollutionFlow = TaintTracking::GlobalWithState<PrototypePollutionConfig>;
62+
63+
/**
64+
* DEPRECATED. Use the `PrototypePollutionFlow` module instead.
65+
*/
66+
deprecated class Configuration extends TaintTracking::Configuration {
2667
Configuration() { this = "PrototypePollution" }
2768

2869
override predicate isSource(DataFlow::Node node, DataFlow::FlowLabel label) {

javascript/ql/src/Security/CWE-915/PrototypePollutingMergeCall.ql

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,11 @@
1919

2020
import javascript
2121
import semmle.javascript.security.dataflow.PrototypePollutionQuery
22-
import DataFlow::PathGraph
22+
import DataFlow::DeduplicatePathGraph<PrototypePollutionFlow::PathNode, PrototypePollutionFlow::PathGraph>
2323

24-
from
25-
Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, string moduleName,
26-
Locatable dependencyLoc
24+
from PathNode source, PathNode sink, string moduleName, Locatable dependencyLoc
2725
where
28-
cfg.hasFlowPath(source, sink) and
26+
PrototypePollutionFlow::flowPath(source.getAnOriginalPathNode(), sink.getAnOriginalPathNode()) and
2927
sink.getNode().(Sink).dependencyInfo(moduleName, dependencyLoc)
3028
select sink.getNode(), source, sink,
3129
"Prototype pollution caused by merging a $@ using a vulnerable version of $@.", source,

javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingMergeCall/PrototypePollutingMergeCall.expected

Lines changed: 42 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,62 @@
11
nodes
2-
| angularmerge.js:1:30:1:34 | event |
3-
| angularmerge.js:1:30:1:34 | event |
4-
| angularmerge.js:2:21:2:42 | JSON.pa ... t.data) |
5-
| angularmerge.js:2:21:2:42 | JSON.pa ... t.data) |
6-
| angularmerge.js:2:32:2:36 | event |
7-
| angularmerge.js:2:32:2:41 | event.data |
8-
| src-vulnerable-lodash/tst.js:7:17:7:29 | req.query.foo |
9-
| src-vulnerable-lodash/tst.js:7:17:7:29 | req.query.foo |
10-
| src-vulnerable-lodash/tst.js:7:17:7:29 | req.query.foo |
11-
| src-vulnerable-lodash/tst.js:10:17:12:5 | {\\n ... K\\n } |
12-
| src-vulnerable-lodash/tst.js:10:17:12:5 | {\\n ... K\\n } |
13-
| src-vulnerable-lodash/tst.js:11:16:11:30 | req.query.value |
14-
| src-vulnerable-lodash/tst.js:11:16:11:30 | req.query.value |
15-
| src-vulnerable-lodash/tst.js:15:14:15:28 | req.query.value |
16-
| src-vulnerable-lodash/tst.js:15:14:15:28 | req.query.value |
17-
| src-vulnerable-lodash/tst.js:17:17:19:5 | {\\n ... K\\n } |
18-
| src-vulnerable-lodash/tst.js:17:17:19:5 | {\\n ... K\\n } |
19-
| src-vulnerable-lodash/tst.js:18:16:18:25 | opts.thing |
20-
| webix/webix.html:3:34:3:38 | event |
21-
| webix/webix.html:3:34:3:38 | event |
22-
| webix/webix.html:4:26:4:47 | JSON.pa ... t.data) |
23-
| webix/webix.html:4:26:4:47 | JSON.pa ... t.data) |
24-
| webix/webix.html:4:37:4:41 | event |
25-
| webix/webix.html:4:37:4:46 | event.data |
26-
| webix/webix.html:5:24:5:45 | JSON.pa ... t.data) |
27-
| webix/webix.html:5:24:5:45 | JSON.pa ... t.data) |
28-
| webix/webix.html:5:35:5:39 | event |
29-
| webix/webix.html:5:35:5:44 | event.data |
30-
| webix/webix.js:3:30:3:34 | event |
31-
| webix/webix.js:3:30:3:34 | event |
32-
| webix/webix.js:4:22:4:43 | JSON.pa ... t.data) |
33-
| webix/webix.js:4:22:4:43 | JSON.pa ... t.data) |
34-
| webix/webix.js:4:33:4:37 | event |
35-
| webix/webix.js:4:33:4:42 | event.data |
36-
| webix/webix.js:5:20:5:41 | JSON.pa ... t.data) |
37-
| webix/webix.js:5:20:5:41 | JSON.pa ... t.data) |
38-
| webix/webix.js:5:31:5:35 | event |
39-
| webix/webix.js:5:31:5:40 | event.data |
2+
| angularmerge.js:1:30:1:34 | event | semmle.label | event |
3+
| angularmerge.js:2:21:2:42 | JSON.pa ... t.data) | semmle.label | JSON.pa ... t.data) |
4+
| angularmerge.js:2:32:2:36 | event | semmle.label | event |
5+
| angularmerge.js:2:32:2:41 | event.data | semmle.label | event.data |
6+
| src-vulnerable-lodash/tst.js:7:17:7:29 | req.query.foo | semmle.label | req.query.foo |
7+
| src-vulnerable-lodash/tst.js:10:17:12:5 | [post update] {\\n ... K\\n } [value] | semmle.label | [post update] {\\n ... K\\n } [value] |
8+
| src-vulnerable-lodash/tst.js:10:17:12:5 | {\\n ... K\\n } | semmle.label | {\\n ... K\\n } |
9+
| src-vulnerable-lodash/tst.js:10:17:12:5 | {\\n ... K\\n } [value] | semmle.label | {\\n ... K\\n } [value] |
10+
| src-vulnerable-lodash/tst.js:11:16:11:30 | req.query.value | semmle.label | req.query.value |
11+
| src-vulnerable-lodash/tst.js:14:9:16:5 | opts [thing] | semmle.label | opts [thing] |
12+
| src-vulnerable-lodash/tst.js:14:16:16:5 | {\\n ... e\\n } [thing] | semmle.label | {\\n ... e\\n } [thing] |
13+
| src-vulnerable-lodash/tst.js:15:14:15:28 | req.query.value | semmle.label | req.query.value |
14+
| src-vulnerable-lodash/tst.js:17:17:19:5 | [post update] {\\n ... K\\n } [value] | semmle.label | [post update] {\\n ... K\\n } [value] |
15+
| src-vulnerable-lodash/tst.js:17:17:19:5 | {\\n ... K\\n } | semmle.label | {\\n ... K\\n } |
16+
| src-vulnerable-lodash/tst.js:17:17:19:5 | {\\n ... K\\n } [value] | semmle.label | {\\n ... K\\n } [value] |
17+
| src-vulnerable-lodash/tst.js:18:16:18:19 | opts [thing] | semmle.label | opts [thing] |
18+
| src-vulnerable-lodash/tst.js:18:16:18:25 | opts.thing | semmle.label | opts.thing |
19+
| webix/webix.html:3:34:3:38 | event | semmle.label | event |
20+
| webix/webix.html:4:26:4:47 | JSON.pa ... t.data) | semmle.label | JSON.pa ... t.data) |
21+
| webix/webix.html:4:37:4:41 | event | semmle.label | event |
22+
| webix/webix.html:4:37:4:46 | event.data | semmle.label | event.data |
23+
| webix/webix.html:5:24:5:45 | JSON.pa ... t.data) | semmle.label | JSON.pa ... t.data) |
24+
| webix/webix.html:5:35:5:39 | event | semmle.label | event |
25+
| webix/webix.html:5:35:5:44 | event.data | semmle.label | event.data |
26+
| webix/webix.js:3:30:3:34 | event | semmle.label | event |
27+
| webix/webix.js:4:22:4:43 | JSON.pa ... t.data) | semmle.label | JSON.pa ... t.data) |
28+
| webix/webix.js:4:33:4:37 | event | semmle.label | event |
29+
| webix/webix.js:4:33:4:42 | event.data | semmle.label | event.data |
30+
| webix/webix.js:5:20:5:41 | JSON.pa ... t.data) | semmle.label | JSON.pa ... t.data) |
31+
| webix/webix.js:5:31:5:35 | event | semmle.label | event |
32+
| webix/webix.js:5:31:5:40 | event.data | semmle.label | event.data |
4033
edges
4134
| angularmerge.js:1:30:1:34 | event | angularmerge.js:2:32:2:36 | event |
42-
| angularmerge.js:1:30:1:34 | event | angularmerge.js:2:32:2:36 | event |
4335
| angularmerge.js:2:32:2:36 | event | angularmerge.js:2:32:2:41 | event.data |
4436
| angularmerge.js:2:32:2:41 | event.data | angularmerge.js:2:21:2:42 | JSON.pa ... t.data) |
45-
| angularmerge.js:2:32:2:41 | event.data | angularmerge.js:2:21:2:42 | JSON.pa ... t.data) |
46-
| src-vulnerable-lodash/tst.js:7:17:7:29 | req.query.foo | src-vulnerable-lodash/tst.js:7:17:7:29 | req.query.foo |
47-
| src-vulnerable-lodash/tst.js:11:16:11:30 | req.query.value | src-vulnerable-lodash/tst.js:10:17:12:5 | {\\n ... K\\n } |
48-
| src-vulnerable-lodash/tst.js:11:16:11:30 | req.query.value | src-vulnerable-lodash/tst.js:10:17:12:5 | {\\n ... K\\n } |
49-
| src-vulnerable-lodash/tst.js:11:16:11:30 | req.query.value | src-vulnerable-lodash/tst.js:10:17:12:5 | {\\n ... K\\n } |
50-
| src-vulnerable-lodash/tst.js:11:16:11:30 | req.query.value | src-vulnerable-lodash/tst.js:10:17:12:5 | {\\n ... K\\n } |
51-
| src-vulnerable-lodash/tst.js:15:14:15:28 | req.query.value | src-vulnerable-lodash/tst.js:18:16:18:25 | opts.thing |
52-
| src-vulnerable-lodash/tst.js:15:14:15:28 | req.query.value | src-vulnerable-lodash/tst.js:18:16:18:25 | opts.thing |
53-
| src-vulnerable-lodash/tst.js:18:16:18:25 | opts.thing | src-vulnerable-lodash/tst.js:17:17:19:5 | {\\n ... K\\n } |
54-
| src-vulnerable-lodash/tst.js:18:16:18:25 | opts.thing | src-vulnerable-lodash/tst.js:17:17:19:5 | {\\n ... K\\n } |
55-
| webix/webix.html:3:34:3:38 | event | webix/webix.html:4:37:4:41 | event |
37+
| src-vulnerable-lodash/tst.js:10:17:12:5 | [post update] {\\n ... K\\n } [value] | src-vulnerable-lodash/tst.js:10:17:12:5 | {\\n ... K\\n } [value] |
38+
| src-vulnerable-lodash/tst.js:10:17:12:5 | {\\n ... K\\n } [value] | src-vulnerable-lodash/tst.js:10:17:12:5 | {\\n ... K\\n } |
39+
| src-vulnerable-lodash/tst.js:11:16:11:30 | req.query.value | src-vulnerable-lodash/tst.js:10:17:12:5 | [post update] {\\n ... K\\n } [value] |
40+
| src-vulnerable-lodash/tst.js:14:9:16:5 | opts [thing] | src-vulnerable-lodash/tst.js:18:16:18:19 | opts [thing] |
41+
| src-vulnerable-lodash/tst.js:14:16:16:5 | {\\n ... e\\n } [thing] | src-vulnerable-lodash/tst.js:14:9:16:5 | opts [thing] |
42+
| src-vulnerable-lodash/tst.js:15:14:15:28 | req.query.value | src-vulnerable-lodash/tst.js:14:16:16:5 | {\\n ... e\\n } [thing] |
43+
| src-vulnerable-lodash/tst.js:17:17:19:5 | [post update] {\\n ... K\\n } [value] | src-vulnerable-lodash/tst.js:17:17:19:5 | {\\n ... K\\n } [value] |
44+
| src-vulnerable-lodash/tst.js:17:17:19:5 | {\\n ... K\\n } [value] | src-vulnerable-lodash/tst.js:17:17:19:5 | {\\n ... K\\n } |
45+
| src-vulnerable-lodash/tst.js:18:16:18:19 | opts [thing] | src-vulnerable-lodash/tst.js:18:16:18:25 | opts.thing |
46+
| src-vulnerable-lodash/tst.js:18:16:18:25 | opts.thing | src-vulnerable-lodash/tst.js:17:17:19:5 | [post update] {\\n ... K\\n } [value] |
5647
| webix/webix.html:3:34:3:38 | event | webix/webix.html:4:37:4:41 | event |
5748
| webix/webix.html:3:34:3:38 | event | webix/webix.html:5:35:5:39 | event |
58-
| webix/webix.html:3:34:3:38 | event | webix/webix.html:5:35:5:39 | event |
5949
| webix/webix.html:4:37:4:41 | event | webix/webix.html:4:37:4:46 | event.data |
6050
| webix/webix.html:4:37:4:46 | event.data | webix/webix.html:4:26:4:47 | JSON.pa ... t.data) |
61-
| webix/webix.html:4:37:4:46 | event.data | webix/webix.html:4:26:4:47 | JSON.pa ... t.data) |
6251
| webix/webix.html:5:35:5:39 | event | webix/webix.html:5:35:5:44 | event.data |
6352
| webix/webix.html:5:35:5:44 | event.data | webix/webix.html:5:24:5:45 | JSON.pa ... t.data) |
64-
| webix/webix.html:5:35:5:44 | event.data | webix/webix.html:5:24:5:45 | JSON.pa ... t.data) |
65-
| webix/webix.js:3:30:3:34 | event | webix/webix.js:4:33:4:37 | event |
6653
| webix/webix.js:3:30:3:34 | event | webix/webix.js:4:33:4:37 | event |
6754
| webix/webix.js:3:30:3:34 | event | webix/webix.js:5:31:5:35 | event |
68-
| webix/webix.js:3:30:3:34 | event | webix/webix.js:5:31:5:35 | event |
6955
| webix/webix.js:4:33:4:37 | event | webix/webix.js:4:33:4:42 | event.data |
7056
| webix/webix.js:4:33:4:42 | event.data | webix/webix.js:4:22:4:43 | JSON.pa ... t.data) |
71-
| webix/webix.js:4:33:4:42 | event.data | webix/webix.js:4:22:4:43 | JSON.pa ... t.data) |
7257
| webix/webix.js:5:31:5:35 | event | webix/webix.js:5:31:5:40 | event.data |
7358
| webix/webix.js:5:31:5:40 | event.data | webix/webix.js:5:20:5:41 | JSON.pa ... t.data) |
74-
| webix/webix.js:5:31:5:40 | event.data | webix/webix.js:5:20:5:41 | JSON.pa ... t.data) |
59+
subpaths
7560
#select
7661
| angularmerge.js:2:21:2:42 | JSON.pa ... t.data) | angularmerge.js:1:30:1:34 | event | angularmerge.js:2:21:2:42 | JSON.pa ... t.data) | Prototype pollution caused by merging a $@ using a vulnerable version of $@. | angularmerge.js:1:30:1:34 | event | user-controlled value | angularmerge.js:2:3:2:43 | angular ... .data)) | angular |
7762
| src-vulnerable-lodash/tst.js:7:17:7:29 | req.query.foo | src-vulnerable-lodash/tst.js:7:17:7:29 | req.query.foo | src-vulnerable-lodash/tst.js:7:17:7:29 | req.query.foo | Prototype pollution caused by merging a $@ using a vulnerable version of $@. | src-vulnerable-lodash/tst.js:7:17:7:29 | req.query.foo | user-controlled value | src-vulnerable-lodash/package.json:3:19:3:26 | "4.17.4" | lodash |

0 commit comments

Comments
 (0)