Skip to content

Commit 56ed68b

Browse files
authored
Merge pull request #9001 from RasmusWL/files-refactoring
Python: Flask: Improve `request.files` modeing
2 parents 249f771 + 7e1be31 commit 56ed68b

File tree

3 files changed

+13
-10
lines changed

3 files changed

+13
-10
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
The modeling of `request.files` in Flask has been fixed, so we now properly handle
5+
assignments to local variables (such as `files = request.files; files['key'].filename`).

python/ql/lib/semmle/python/frameworks/Flask.qll

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -411,21 +411,16 @@ module Flask {
411411
/** An `FileStorage` instance that originates from a flask request. */
412412
private class FlaskRequestFileStorageInstances extends Werkzeug::FileStorage::InstanceSource {
413413
FlaskRequestFileStorageInstances() {
414-
// TODO: this currently only works in local-scope, since writing type-trackers for
415-
// this is a little too much effort. Once API-graphs are available for more
416-
// things, we can rewrite this.
417-
//
418414
// TODO: This approach for identifying member-access is very adhoc, and we should
419415
// be able to do something more structured for providing modeling of the members
420416
// of a container-object.
421-
exists(DataFlow::AttrRead files | files = request().getMember("files").getAnImmediateUse() |
422-
this.asCfgNode().(SubscriptNode).getObject() = files.asCfgNode()
417+
exists(API::Node files | files = request().getMember("files") |
418+
this.asCfgNode().(SubscriptNode).getObject() = files.getAUse().asCfgNode()
423419
or
424-
this.(DataFlow::MethodCallNode).calls(files, "get")
420+
this = files.getMember("get").getACall()
425421
or
426-
exists(DataFlow::MethodCallNode getlistCall | getlistCall.calls(files, "getlist") |
427-
this.asCfgNode().(SubscriptNode).getObject() = getlistCall.asCfgNode()
428-
)
422+
this.asCfgNode().(SubscriptNode).getObject() =
423+
files.getMember("getlist").getReturn().getAUse().asCfgNode()
429424
)
430425
}
431426
}

python/ql/test/library-tests/frameworks/flask/taint_test.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ def test_taint(name = "World!", number="0", foo="foo"): # $requestHandler route
189189
a = request.args
190190
b = a
191191
gl = b.getlist
192+
files = request.files
192193
ensure_tainted(
193194
request.args, # $ tainted
194195
a, # $ tainted
@@ -202,6 +203,8 @@ def test_taint(name = "World!", number="0", foo="foo"): # $requestHandler route
202203
a.getlist('key'), # $ tainted
203204
b.getlist('key'), # $ tainted
204205
gl('key'), # $ tainted
206+
207+
files.get('key').filename, # $ tainted
205208
)
206209

207210
# aliasing tests

0 commit comments

Comments
 (0)