File tree Expand file tree Collapse file tree 6 files changed +87
-2
lines changed
src/semmle/python/web/flask
test/library-tests/web/flask Expand file tree Collapse file tree 6 files changed +87
-2
lines changed Original file line number Diff line number Diff line change @@ -54,3 +54,35 @@ class FlaskRequestJson extends HttpRequestTaintSource {
54
54
55
55
override string toString ( ) { result = "flask.request.json" }
56
56
}
57
+
58
+ /**
59
+ * A parameter to a flask request handler, that can capture a part of the URL (as specified in
60
+ * the url-pattern of a route).
61
+ *
62
+ * For example, the `name` parameter in:
63
+ * ```
64
+ * @app.route('/hello/<name>')
65
+ * def hello(name):
66
+ * ```
67
+ */
68
+ class FlaskRoutedParameter extends HttpRequestTaintSource {
69
+ FlaskRoutedParameter ( ) {
70
+ exists ( string name , Function func , StrConst url_pattern |
71
+ this .( ControlFlowNode ) .getNode ( ) = func .getArgByName ( name ) and
72
+ flask_routing ( url_pattern .getAFlowNode ( ) , func ) and
73
+ exists ( string match |
74
+ match = url_pattern .getS ( ) .regexpFind ( werkzeug_rule_re ( ) , _, _) and
75
+ name = match .regexpCapture ( werkzeug_rule_re ( ) , 4 )
76
+ )
77
+ )
78
+ }
79
+
80
+ override predicate isSourceOf ( TaintKind kind ) { kind instanceof ExternalStringKind }
81
+ }
82
+
83
+ private string werkzeug_rule_re ( ) {
84
+ // since flask uses werkzeug internally, we are using its routing rules from
85
+ // https://github.com/pallets/werkzeug/blob/4dc8d6ab840d4b78cbd5789cef91b01e3bde01d5/src/werkzeug/routing.py#L138-L151
86
+ result =
87
+ "(?<static>[^<]*)<(?:(?<converter>[a-zA-Z_][a-zA-Z0-9_]*)(?:\\((?<args>.*?)\\))?\\:)?(?<variable>[a-zA-Z_][a-zA-Z0-9_]*)>"
88
+ }
Original file line number Diff line number Diff line change 6
6
| test.py:41:26:41:53 | flask.response.argument | externally controlled string |
7
7
| test.py:46:12:46:62 | flask.routed.response | externally controlled string |
8
8
| test.py:46:26:46:61 | flask.response.argument | externally controlled string |
9
+ | test.py:50:12:50:48 | flask.routed.response | externally controlled string |
10
+ | test.py:50:26:50:47 | flask.response.argument | externally controlled string |
11
+ | test.py:54:12:54:53 | flask.routed.response | externally controlled string |
12
+ | test.py:54:26:54:52 | flask.response.argument | externally controlled string |
13
+ | test.py:60:12:60:62 | flask.routed.response | externally controlled string |
14
+ | test.py:60:26:60:61 | flask.response.argument | externally controlled string |
15
+ | test.py:64:12:64:58 | flask.routed.response | externally controlled string |
16
+ | test.py:64:26:64:57 | flask.response.argument | externally controlled string |
Original file line number Diff line number Diff line change 3
3
| test.py:35:16:35:27 | Attribute | {externally controlled string} |
4
4
| test.py:40:18:40:29 | Attribute | {externally controlled string} |
5
5
| test.py:45:18:45:29 | Attribute | {externally controlled string} |
6
+ | test.py:49:11:49:14 | name | externally controlled string |
7
+ | test.py:53:9:53:15 | subpath | externally controlled string |
8
+ | test.py:59:24:59:26 | bar | externally controlled string |
9
+ | test.py:63:13:63:21 | lang_code | externally controlled string |
Original file line number Diff line number Diff line change 1
- | / | Function hello |
1
+ | / | Function hello_world |
2
+ | /complex/<string(length=2):lang_code> | Function complex |
2
3
| /dangerous | Function dangerous |
3
4
| /dangerous-with-cfg-split | Function dangerous2 |
5
+ | /foo/<path:subpath> | Function foo |
6
+ | /hello/<name> | Function hello |
7
+ | /multiple/bar/<bar> | Function multiple |
4
8
| /safe | Function safe |
5
9
| /the/ | Function get |
6
10
| /unsafe | Function unsafe |
Original file line number Diff line number Diff line change 15
15
| test.py:45 | Attribute() | externally controlled string |
16
16
| test.py:46 | first_name | externally controlled string |
17
17
| test.py:46 | make_response() | flask.Response |
18
+ | test.py:49 | name | externally controlled string |
19
+ | test.py:50 | BinaryExpr | externally controlled string |
20
+ | test.py:50 | make_response() | flask.Response |
21
+ | test.py:50 | name | externally controlled string |
22
+ | test.py:53 | subpath | externally controlled string |
23
+ | test.py:54 | BinaryExpr | externally controlled string |
24
+ | test.py:54 | make_response() | flask.Response |
25
+ | test.py:54 | subpath | externally controlled string |
26
+ | test.py:59 | bar | externally controlled string |
27
+ | test.py:60 | Attribute() | externally controlled string |
28
+ | test.py:60 | bar | externally controlled string |
29
+ | test.py:60 | make_response() | flask.Response |
30
+ | test.py:63 | lang_code | externally controlled string |
31
+ | test.py:64 | Attribute() | externally controlled string |
32
+ | test.py:64 | lang_code | externally controlled string |
33
+ | test.py:64 | make_response() | flask.Response |
Original file line number Diff line number Diff line change 4
4
app = Flask (__name__ )
5
5
6
6
@app .route ("/" )
7
- def hello ():
7
+ def hello_world ():
8
8
return "Hello World!"
9
9
10
10
from flask .views import MethodView
@@ -44,3 +44,24 @@ def unsafe():
44
44
def safe ():
45
45
first_name = request .args .get ('name' , '' )
46
46
return make_response ("Your name is " + escape (first_name ))
47
+
48
+ @app .route ('/hello/<name>' )
49
+ def hello (name ):
50
+ return make_response ("Your name is " + name )
51
+
52
+ @app .route ('/foo/<path:subpath>' )
53
+ def foo (subpath ):
54
+ return make_response ("The subpath is " + subpath )
55
+
56
+ @app .route ('/multiple/' ) # TODO: not recognized as route
57
+ @app .route ('/multiple/foo/<foo>' ) # TODO: not recognized as route
58
+ @app .route ('/multiple/bar/<bar>' )
59
+ def multiple (foo = None , bar = None ):
60
+ return make_response ("foo={!r} bar={!r}" .format (foo , bar ))
61
+
62
+ @app .route ('/complex/<string(length=2):lang_code>' )
63
+ def complex (lang_code ):
64
+ return make_response ("lang_code {}" .format (lang_code ))
65
+
66
+ if __name__ == "__main__" :
67
+ app .run (debug = True )
You can’t perform that action at this time.
0 commit comments