@@ -139,6 +139,8 @@ class ParamsSource extends Http::Server::RequestInputAccess::Range {
139139 ParamsSource ( ) { this .asExpr ( ) .getExpr ( ) instanceof Rails:: ParamsCall }
140140
141141 override string getSourceType ( ) { result = "ActionController::Metal#params" }
142+
143+ override Http:: Server:: RequestInputKind getKind ( ) { result = Http:: Server:: parameterInputKind ( ) }
142144}
143145
144146/**
@@ -149,6 +151,8 @@ class CookiesSource extends Http::Server::RequestInputAccess::Range {
149151 CookiesSource ( ) { this .asExpr ( ) .getExpr ( ) instanceof Rails:: CookiesCall }
150152
151153 override string getSourceType ( ) { result = "ActionController::Metal#cookies" }
154+
155+ override Http:: Server:: RequestInputKind getKind ( ) { result = Http:: Server:: cookieInputKind ( ) }
152156}
153157
154158/** A call to `cookies` from within a controller. */
@@ -161,6 +165,140 @@ private class ActionControllerParamsCall extends ActionControllerContextCall, Pa
161165 ActionControllerParamsCall ( ) { this .getMethodName ( ) = "params" }
162166}
163167
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+
164302/** A call to `render` from within a controller. */
165303private class ActionControllerRenderCall extends ActionControllerContextCall , RenderCallImpl {
166304 ActionControllerRenderCall ( ) { this .getMethodName ( ) = "render" }
0 commit comments