4
4
*/
5
5
6
6
private import python
7
+ private import semmle.python.dataflow.new.DataFlow
7
8
private import semmle.python.Concepts
8
9
private import semmle.python.ApiGraphs
9
10
private import semmle.python.dataflow.new.RemoteFlowSources
10
11
private import semmle.python.frameworks.internal.InstanceTaintStepsHelper
12
+ private import semmle.python.frameworks.Stdlib
13
+ private import semmle.python.dataflow.new.RemoteFlowSources
11
14
12
15
/**
13
16
* INTERNAL: Do not use.
@@ -21,11 +24,65 @@ module Bottle {
21
24
22
25
/** Provides models for the `bottle` module. */
23
26
module BottleModule {
27
+ module App {
28
+ API:: Node cls ( ) { result = API:: moduleImport ( "bottle" ) .getMember ( "Bottle" ) }
29
+
30
+ /** Gets a reference to a FastAPI application (an instance of `fastapi.FastAPI`). */
31
+ API:: Node instance ( ) { result = cls ( ) .getReturn ( ) }
32
+
33
+ API:: Node app ( ) { result = bottle ( ) .getMember ( "app" ) .getReturn ( ) }
34
+ }
35
+
36
+ /** Provides models for functions that are possible "views" */
37
+ module View {
38
+ /**
39
+ * A Bottle view callable, that handles incoming requests.
40
+ */
41
+ class ViewCallable extends Function {
42
+ ViewCallable ( ) { this = any ( BottleRouteSetup rs ) .getARequestHandler ( ) }
43
+ }
44
+
45
+ private class BottleRouteSetup extends Http:: Server:: RouteSetup:: Range , DataFlow:: CallCfgNode {
46
+ BottleRouteSetup ( ) {
47
+ this =
48
+ [
49
+ App:: instance ( )
50
+ .getMember ( [ "route" , "get" , "post" , "put" , "delete" , "patch" ] )
51
+ .getACall ( ) ,
52
+ App:: app ( ) .getMember ( [ "route" , "get" , "post" , "put" , "delete" , "patch" ] ) .getACall ( ) ,
53
+ bottle ( ) .getMember ( [ "route" , "get" , "post" , "put" , "delete" , "patch" ] ) .getACall ( )
54
+ ]
55
+ }
56
+
57
+ override DataFlow:: Node getUrlPatternArg ( ) {
58
+ result in [ this .getArg ( 0 ) , this .getArgByName ( "route" ) ]
59
+ }
60
+
61
+ override string getFramework ( ) { result = "Bottle" }
62
+
63
+ override Parameter getARoutedParameter ( ) { none ( ) }
64
+
65
+ override Function getARequestHandler ( ) { result .getADecorator ( ) .getAFlowNode ( ) = node }
66
+ }
67
+ }
68
+
24
69
/** Provides models for the `bottle.response` module */
25
70
module Response {
26
71
/** Gets a reference to the `bottle.response` module. */
27
72
API:: Node response ( ) { result = bottle ( ) .getMember ( "response" ) }
28
73
74
+ class BottleReturnResponse extends Http:: Server:: HttpResponse:: Range {
75
+ BottleReturnResponse ( ) {
76
+ this .asCfgNode ( ) = any ( View:: ViewCallable vc ) .getAReturnValueFlowNode ( )
77
+ }
78
+
79
+ override DataFlow:: Node getBody ( ) { result = this }
80
+
81
+ override DataFlow:: Node getMimetypeOrContentTypeArg ( ) { none ( ) }
82
+
83
+ override string getMimetypeDefault ( ) { result = "text/html" }
84
+ }
85
+
29
86
/**
30
87
* A call to the `bottle.BaseResponse.set_header` or `bottle.BaseResponse.add_header` method.
31
88
*
@@ -50,66 +107,68 @@ module Bottle {
50
107
51
108
override predicate valueAllowsNewline ( ) { none ( ) }
52
109
}
110
+ }
53
111
54
- /** Provides models for the `bottle.request` module */
55
- module Request {
56
- /** Gets a reference to the `bottle.request` module. */
57
- API:: Node request ( ) { result = bottle ( ) .getMember ( "request" ) }
58
-
59
- private class Request extends RemoteFlowSource:: Range {
60
- Request ( ) { this = request ( ) .asSource ( ) }
61
-
62
- override string getSourceType ( ) { result = "bottle.request" }
63
- }
112
+ /** Provides models for the `bottle.request` module */
113
+ module Request {
114
+ /** Gets a reference to the `bottle.request` module. */
115
+ API:: Node request ( ) { result = bottle ( ) .getMember ( "request" ) }
64
116
65
- /**
66
- * Taint propagation for `bottle.request`.
67
- *
68
- * See https://bottlepy.org/docs/dev/api.html#bottle.request
69
- */
70
- private class InstanceTaintSteps extends InstanceTaintStepsHelper {
71
- InstanceTaintSteps ( ) { this = "bottle.request" }
117
+ private class Request extends RemoteFlowSource:: Range {
118
+ Request ( ) { this = request ( ) .asSource ( ) }
72
119
73
- override DataFlow:: Node getInstance ( ) {
74
- result = request ( ) .getAValueReachableFromSource ( )
75
- }
120
+ override string getSourceType ( ) { result = "bottle.request" }
121
+ }
76
122
77
- override string getAttributeName ( ) {
78
- result in [ "headers" , "query" , "forms" , "params" , "json" , "url" ]
79
- }
123
+ /**
124
+ * Taint propagation for `bottle.request`.
125
+ *
126
+ * See https://bottlepy.org/docs/dev/api.html#bottle.request
127
+ */
128
+ private class InstanceTaintSteps extends InstanceTaintStepsHelper {
129
+ InstanceTaintSteps ( ) { this = "bottle.request" }
80
130
81
- override string getMethodName ( ) { none ( ) }
131
+ override DataFlow :: Node getInstance ( ) { result = request ( ) . getAValueReachableFromSource ( ) }
82
132
83
- override string getAsyncMethodName ( ) { none ( ) }
133
+ override string getAttributeName ( ) {
134
+ result in [
135
+ "headers" , "query" , "forms" , "params" , "json" , "url" , "body" , "fullpath" ,
136
+ "query_string"
137
+ ]
84
138
}
85
- }
86
139
87
- /** Provides models for the `bottle.headers` module */
88
- module Headers {
89
- /** Gets a reference to the `bottle.headers` module. */
90
- API:: Node headers ( ) { result = bottle ( ) .getMember ( "response" ) .getMember ( "headers" ) }
140
+ override string getMethodName ( ) { none ( ) }
91
141
92
- /** A dict-like write to a response header. */
93
- class HeaderWriteSubscript extends Http:: Server:: ResponseHeaderWrite:: Range , DataFlow:: Node {
94
- API:: Node name ;
95
- API:: Node value ;
142
+ override string getAsyncMethodName ( ) { none ( ) }
143
+ }
144
+ }
96
145
97
- HeaderWriteSubscript ( ) {
98
- exists ( API:: Node holder |
99
- holder = headers ( ) and
100
- this = holder .asSource ( ) and
101
- value = holder .getSubscriptAt ( name )
102
- )
103
- }
146
+ /** Provides models for the `bottle.headers` module */
147
+ module Headers {
148
+ /** Gets a reference to the `bottle.headers` module. */
149
+ API:: Node headers ( ) { result = bottle ( ) .getMember ( "response" ) .getMember ( "headers" ) }
150
+
151
+ /** A dict-like write to a response header. */
152
+ class HeaderWriteSubscript extends Http:: Server:: ResponseHeaderWrite:: Range , DataFlow:: Node {
153
+ DataFlow:: Node name ;
154
+ DataFlow:: Node value ;
155
+
156
+ HeaderWriteSubscript ( ) {
157
+ exists ( SubscriptNode subscript |
158
+ this .asCfgNode ( ) = subscript and
159
+ value .asCfgNode ( ) = subscript .( DefinitionNode ) .getValue ( ) and
160
+ name .asCfgNode ( ) = subscript .getIndex ( ) and
161
+ subscript .getObject ( ) = headers ( ) .asSource ( ) .asCfgNode ( )
162
+ )
163
+ }
104
164
105
- override DataFlow:: Node getNameArg ( ) { result = name . asSink ( ) }
165
+ override DataFlow:: Node getNameArg ( ) { result = name }
106
166
107
- override DataFlow:: Node getValueArg ( ) { result = value . asSink ( ) }
167
+ override DataFlow:: Node getValueArg ( ) { result = value }
108
168
109
- override predicate nameAllowsNewline ( ) { none ( ) }
169
+ override predicate nameAllowsNewline ( ) { none ( ) }
110
170
111
- override predicate valueAllowsNewline ( ) { none ( ) }
112
- }
171
+ override predicate valueAllowsNewline ( ) { none ( ) }
113
172
}
114
173
}
115
174
}
0 commit comments