Skip to content

Commit d0fdb54

Browse files
committed
Python: Modernise werkzeug MultiDict modeling
1 parent b6bd70a commit d0fdb54

File tree

2 files changed

+65
-29
lines changed

2 files changed

+65
-29
lines changed

python/ql/src/experimental/semmle/python/frameworks/Flask.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ private module Flask_Private {
317317
}
318318

319319
private class RequestInputMultiDict extends RequestInputAccess,
320-
Werkzeug::Datastructures::MultiDict {
320+
Werkzeug::werkzeug::datastructures::MultiDict::InstanceSource {
321321
RequestInputMultiDict() { attr_name in ["args", "values", "form", "files"] }
322322
}
323323

python/ql/src/experimental/semmle/python/frameworks/Werkzeug.qll

Lines changed: 64 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,76 @@ private import experimental.dataflow.DataFlow
77
private import experimental.dataflow.TaintTracking
88

99
module Werkzeug {
10-
module Datastructures {
11-
// ---------------------------------------------------------------------- //
12-
// MultiDict //
13-
// ---------------------------------------------------------------------- //
14-
/**
15-
* A Node representing an instance of a werkzeug.datastructures.MultiDict
16-
*
17-
* See https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.MultiDict
18-
*/
19-
abstract class MultiDict extends DataFlow::Node { }
10+
/** Provides models for the `werkzeug` module. */
11+
module werkzeug {
12+
/** Provides models for the `werkzeug.datastructures` module. */
13+
module datastructures {
14+
/**
15+
* Provides models for the `werkzeug.datastructures.MultiDict` class
16+
*
17+
* See https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.MultiDict.
18+
*/
19+
module MultiDict {
20+
/**
21+
* A source of an instance of `werkzeug.datastructures.MultiDict`.
22+
*
23+
* This can include instantiation of the class, return value from function
24+
* calls, or a special parameter that will be set when functions are call by external
25+
* library.
26+
*
27+
* Use `MultiDict::instance()` predicate to get references to instances of `werkzeug.datastructures.MultiDict`.
28+
*/
29+
abstract class InstanceSource extends DataFlow::Node { }
2030

21-
private module MultiDictTracking {
22-
private DataFlow::Node getlist(DataFlow::TypeTracker t) {
23-
t.startInAttr("getlist") and
24-
result instanceof MultiDict
25-
or
26-
exists(DataFlow::TypeTracker t2 | result = getlist(t2).track(t2, t))
27-
}
31+
/** Gets a reference to an instance of `werkzeug.datastructures.MultiDict`. */
32+
private DataFlow::Node instance(DataFlow::TypeTracker t) {
33+
t.start() and
34+
result instanceof InstanceSource
35+
or
36+
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
37+
}
2838

29-
DataFlow::Node getlist() { result = getlist(DataFlow::TypeTracker::end()) }
30-
}
39+
/** Gets a reference to an instance of `werkzeug.datastructures.MultiDict`. */
40+
DataFlow::Node instance() { result = instance(DataFlow::TypeTracker::end()) }
3141

32-
private class MultiDictAdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
33-
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
34-
// obj -> obj.getlist
35-
nodeTo.asCfgNode().(AttrNode).getObject("getlist") = nodeFrom.asCfgNode() and
36-
nodeTo = MultiDictTracking::getlist()
37-
or
38-
// getlist -> getlist()
39-
nodeFrom = MultiDictTracking::getlist() and
40-
nodeTo.asCfgNode().(CallNode).getFunction() = nodeFrom.asCfgNode()
42+
/**
43+
* Gets a reference to the `getlist` method on an instance of `werkzeug.datastructures.MultiDict`.
44+
*
45+
* See https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.Headers.getlist
46+
*/
47+
private DataFlow::Node getlist(DataFlow::TypeTracker t) {
48+
t.startInAttr("getlist") and
49+
result = instance()
50+
or
51+
exists(DataFlow::TypeTracker t2 | result = getlist(t2).track(t2, t))
52+
}
53+
54+
/**
55+
* Gets a reference to the `getlist` method on an instance of `werkzeug.datastructures.MultiDict`.
56+
*
57+
* See https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.Headers.getlist
58+
*/
59+
DataFlow::Node getlist() { result = getlist(DataFlow::TypeTracker::end()) }
4160
}
4261
}
62+
}
4363

64+
private class MultiDictAdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
65+
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
66+
// obj -> obj.getlist
67+
exists(DataFlow::AttrRead read |
68+
read.getObject() = nodeFrom and
69+
nodeTo = read and
70+
nodeTo = werkzeug::datastructures::MultiDict::getlist()
71+
)
72+
or
73+
// getlist -> getlist()
74+
nodeFrom = werkzeug::datastructures::MultiDict::getlist() and
75+
nodeTo.asCfgNode().(CallNode).getFunction() = nodeFrom.asCfgNode()
76+
}
77+
}
78+
79+
module Datastructures {
4480
// ---------------------------------------------------------------------- //
4581
// FileStorage //
4682
// ---------------------------------------------------------------------- //

0 commit comments

Comments
 (0)