@@ -139,6 +139,8 @@ class ParamsSource extends Http::Server::RequestInputAccess::Range {
139
139
ParamsSource ( ) { this .asExpr ( ) .getExpr ( ) instanceof Rails:: ParamsCall }
140
140
141
141
override string getSourceType ( ) { result = "ActionController::Metal#params" }
142
+
143
+ override Http:: Server:: RequestInputKind getKind ( ) { result = Http:: Server:: parameterInputKind ( ) }
142
144
}
143
145
144
146
/**
@@ -149,6 +151,8 @@ class CookiesSource extends Http::Server::RequestInputAccess::Range {
149
151
CookiesSource ( ) { this .asExpr ( ) .getExpr ( ) instanceof Rails:: CookiesCall }
150
152
151
153
override string getSourceType ( ) { result = "ActionController::Metal#cookies" }
154
+
155
+ override Http:: Server:: RequestInputKind getKind ( ) { result = Http:: Server:: cookieInputKind ( ) }
152
156
}
153
157
154
158
/** A call to `cookies` from within a controller. */
@@ -161,6 +165,140 @@ private class ActionControllerParamsCall extends ActionControllerContextCall, Pa
161
165
ActionControllerParamsCall ( ) { this .getMethodName ( ) = "params" }
162
166
}
163
167
168
+ /** Modeling for `ActionDispatch::Request`. */
169
+ private module Request {
170
+ /**
171
+ * A call to `request` from within a controller. This is an instance of
172
+ * `ActionDispatch::Request`.
173
+ */
174
+ private class RequestNode extends DataFlow:: CallNode {
175
+ RequestNode ( ) {
176
+ this .asExpr ( ) .getExpr ( ) instanceof ActionControllerContextCall and
177
+ this .getMethodName ( ) = "request"
178
+ }
179
+ }
180
+
181
+ /**
182
+ * A method call on `request`.
183
+ */
184
+ private class RequestMethodCall extends DataFlow:: CallNode {
185
+ RequestMethodCall ( ) {
186
+ any ( RequestNode r ) .( DataFlow:: LocalSourceNode ) .flowsTo ( this .getReceiver ( ) )
187
+ }
188
+ }
189
+
190
+ abstract private class RequestInputAccess extends RequestMethodCall ,
191
+ Http:: Server:: RequestInputAccess:: Range {
192
+ override string getSourceType ( ) { result = "ActionDispatch::Request#" + this .getMethodName ( ) }
193
+ }
194
+
195
+ /**
196
+ * A method call on `request` which returns request parameters.
197
+ */
198
+ private class ParametersCall extends RequestInputAccess {
199
+ ParametersCall ( ) {
200
+ this .getMethodName ( ) =
201
+ [
202
+ "parameters" , "params" , "GET" , "POST" , "query_parameters" , "request_parameters" ,
203
+ "filtered_parameters"
204
+ ]
205
+ }
206
+
207
+ override Http:: Server:: RequestInputKind getKind ( ) {
208
+ result = Http:: Server:: parameterInputKind ( )
209
+ }
210
+ }
211
+
212
+ /** A method call on `request` which returns part or all of the request path. */
213
+ private class PathCall extends RequestInputAccess {
214
+ PathCall ( ) {
215
+ this .getMethodName ( ) =
216
+ [ "path" , "filtered_path" , "fullpath" , "original_fullpath" , "original_url" , "url" ]
217
+ }
218
+
219
+ override Http:: Server:: RequestInputKind getKind ( ) { result = Http:: Server:: urlInputKind ( ) }
220
+ }
221
+
222
+ /** A method call on `request` which returns a specific request header. */
223
+ private class HeadersCall extends RequestInputAccess {
224
+ HeadersCall ( ) {
225
+ this .getMethodName ( ) =
226
+ [
227
+ "authorization" , "script_name" , "path_info" , "user_agent" , "referer" , "referrer" ,
228
+ "host_authority" , "content_type" , "host" , "hostname" , "accept_encoding" ,
229
+ "accept_language" , "if_none_match" , "if_none_match_etags" , "content_mime_type"
230
+ ]
231
+ or
232
+ // Request headers are prefixed with `HTTP_` to distinguish them from
233
+ // "headers" supplied by Rack middleware.
234
+ this .getMethodName ( ) = [ "get_header" , "fetch_header" ] and
235
+ this .getArgument ( 0 ) .asExpr ( ) .getExpr ( ) .getConstantValue ( ) .getString ( ) .regexpMatch ( "^HTTP_.+" )
236
+ }
237
+
238
+ override Http:: Server:: RequestInputKind getKind ( ) { result = Http:: Server:: headerInputKind ( ) }
239
+ }
240
+
241
+ // TODO: each_header
242
+ /**
243
+ * A method call on `request` which returns part or all of the host.
244
+ * This can be influenced by headers such as Host and X-Forwarded-Host.
245
+ */
246
+ private class HostCall extends RequestInputAccess {
247
+ HostCall ( ) {
248
+ this .getMethodName ( ) =
249
+ [
250
+ "authority" , "host" , "host_authority" , "host_with_port" , "hostname" , "forwarded_for" ,
251
+ "forwarded_host" , "port" , "forwarded_port"
252
+ ]
253
+ }
254
+
255
+ override Http:: Server:: RequestInputKind getKind ( ) { result = Http:: Server:: headerInputKind ( ) }
256
+ }
257
+
258
+ /**
259
+ * A method call on `request` which is influenced by one or more request
260
+ * headers.
261
+ */
262
+ private class HeaderTaintedCall extends RequestInputAccess {
263
+ HeaderTaintedCall ( ) {
264
+ this .getMethodName ( ) = [ "media_type" , "media_type_params" , "content_charset" , "base_url" ]
265
+ }
266
+
267
+ override Http:: Server:: RequestInputKind getKind ( ) { result = Http:: Server:: headerInputKind ( ) }
268
+ }
269
+
270
+ /** A method call on `request` which returns the request body. */
271
+ private class BodyCall extends RequestInputAccess {
272
+ BodyCall ( ) { this .getMethodName ( ) = [ "body" , "raw_post" ] }
273
+
274
+ override Http:: Server:: RequestInputKind getKind ( ) { result = Http:: Server:: bodyInputKind ( ) }
275
+ }
276
+
277
+ /**
278
+ * A method call on `request` which returns the rack env.
279
+ * This is a hash containing all the information about the request. Values
280
+ * under keys starting with `HTTP_` are user-controlled.
281
+ */
282
+ private class EnvCall extends RequestMethodCall {
283
+ EnvCall ( ) { this .getMethodName ( ) = [ "env" , "filtered_env" ] }
284
+ }
285
+
286
+ /**
287
+ * A read of a user-controlled parameter from the request env.
288
+ */
289
+ private class EnvHttpAccess extends DataFlow:: CallNode , Http:: Server:: RequestInputAccess:: Range {
290
+ EnvHttpAccess ( ) {
291
+ any ( EnvCall c ) .( DataFlow:: LocalSourceNode ) .flowsTo ( this .getReceiver ( ) ) and
292
+ this .getMethodName ( ) = "[]" and
293
+ this .getArgument ( 0 ) .asExpr ( ) .getExpr ( ) .getConstantValue ( ) .getString ( ) .regexpMatch ( "^HTTP_.+" )
294
+ }
295
+
296
+ override Http:: Server:: RequestInputKind getKind ( ) { result = Http:: Server:: headerInputKind ( ) }
297
+
298
+ override string getSourceType ( ) { result = "ActionDispatch::Request#env[]" }
299
+ }
300
+ }
301
+
164
302
/** A call to `render` from within a controller. */
165
303
private class ActionControllerRenderCall extends ActionControllerContextCall , RenderCallImpl {
166
304
ActionControllerRenderCall ( ) { this .getMethodName ( ) = "render" }
0 commit comments