Skip to content

Commit e6dc27a

Browse files
committed
Add content_mime_type, fix env/filtered_env
1 parent 0130e4b commit e6dc27a

File tree

3 files changed

+111
-7
lines changed

3 files changed

+111
-7
lines changed

ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ private module Request {
226226
[
227227
"authorization", "script_name", "path_info", "user_agent", "referer", "referrer",
228228
"host_authority", "content_type", "host", "hostname", "accept_encoding",
229-
"accept_language", "if_none_match", "if_none_match_etags"
229+
"accept_language", "if_none_match", "if_none_match_etags", "content_mime_type"
230230
]
231231
or
232232
// Request headers are prefixed with `HTTP_` to distinguish them from
@@ -261,8 +261,7 @@ private module Request {
261261
*/
262262
private class HeaderTaintedCall extends RequestInputAccess {
263263
HeaderTaintedCall() {
264-
this.getMethodName() =
265-
["media_type", "media_type", "media_type_params", "content_charset", "base_url"]
264+
this.getMethodName() = ["media_type", "media_type_params", "content_charset", "base_url"]
266265
}
267266

268267
override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() }
@@ -275,14 +274,28 @@ private module Request {
275274
override Http::Server::RequestInputKind getKind() { result = Http::Server::bodyInputKind() }
276275
}
277276

278-
/** A method call on `request` which returns the rack env. */
279-
private class EnvCall extends RequestInputAccess {
280-
EnvCall() {
281-
this.getMethodName() = ["env", "filtered_env"] and
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
282293
this.getArgument(0).asExpr().getExpr().getConstantValue().getString().regexpMatch("^HTTP_.+")
283294
}
284295

285296
override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() }
297+
298+
override string getSourceType() { result = "ActionDispatch::Request#env[]" }
286299
}
287300
}
288301

ruby/ql/test/library-tests/frameworks/ActionController.expected

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
actionControllerControllerClasses
2+
| action_controller/input_access.rb:1:1:50:3 | UsersController |
23
| action_controller/params_flow.rb:1:1:151:3 | MyController |
34
| active_record/ActiveRecord.rb:23:1:39:3 | FooController |
45
| active_record/ActiveRecord.rb:41:1:64:3 | BarController |
@@ -12,6 +13,7 @@ actionControllerControllerClasses
1213
| app/controllers/tags_controller.rb:1:1:2:3 | TagsController |
1314
| app/controllers/users/notifications_controller.rb:2:3:5:5 | NotificationsController |
1415
actionControllerActionMethods
16+
| action_controller/input_access.rb:2:3:49:5 | index |
1517
| action_controller/params_flow.rb:2:3:4:5 | m1 |
1618
| action_controller/params_flow.rb:6:3:8:5 | m2 |
1719
| action_controller/params_flow.rb:10:3:12:5 | m2 |
@@ -223,6 +225,45 @@ paramsSources
223225
| app/controllers/foo/bars_controller.rb:22:10:22:15 | call to params |
224226
| app/views/foo/bars/show.html.erb:5:9:5:14 | call to params |
225227
httpInputAccesses
228+
| action_controller/input_access.rb:3:5:3:18 | call to params | ActionDispatch::Request#params |
229+
| action_controller/input_access.rb:4:5:4:22 | call to parameters | ActionDispatch::Request#parameters |
230+
| action_controller/input_access.rb:5:5:5:15 | call to GET | ActionDispatch::Request#GET |
231+
| action_controller/input_access.rb:6:5:6:16 | call to POST | ActionDispatch::Request#POST |
232+
| action_controller/input_access.rb:7:5:7:28 | call to query_parameters | ActionDispatch::Request#query_parameters |
233+
| action_controller/input_access.rb:8:5:8:30 | call to request_parameters | ActionDispatch::Request#request_parameters |
234+
| action_controller/input_access.rb:9:5:9:31 | call to filtered_parameters | ActionDispatch::Request#filtered_parameters |
235+
| action_controller/input_access.rb:11:5:11:25 | call to authorization | ActionDispatch::Request#authorization |
236+
| action_controller/input_access.rb:12:5:12:23 | call to script_name | ActionDispatch::Request#script_name |
237+
| action_controller/input_access.rb:13:5:13:21 | call to path_info | ActionDispatch::Request#path_info |
238+
| action_controller/input_access.rb:14:5:14:22 | call to user_agent | ActionDispatch::Request#user_agent |
239+
| action_controller/input_access.rb:15:5:15:19 | call to referer | ActionDispatch::Request#referer |
240+
| action_controller/input_access.rb:16:5:16:20 | call to referrer | ActionDispatch::Request#referrer |
241+
| action_controller/input_access.rb:17:5:17:26 | call to host_authority | ActionDispatch::Request#host_authority |
242+
| action_controller/input_access.rb:18:5:18:24 | call to content_type | ActionDispatch::Request#content_type |
243+
| action_controller/input_access.rb:19:5:19:16 | call to host | ActionDispatch::Request#host |
244+
| action_controller/input_access.rb:20:5:20:20 | call to hostname | ActionDispatch::Request#hostname |
245+
| action_controller/input_access.rb:21:5:21:27 | call to accept_encoding | ActionDispatch::Request#accept_encoding |
246+
| action_controller/input_access.rb:22:5:22:27 | call to accept_language | ActionDispatch::Request#accept_language |
247+
| action_controller/input_access.rb:23:5:23:25 | call to if_none_match | ActionDispatch::Request#if_none_match |
248+
| action_controller/input_access.rb:24:5:24:31 | call to if_none_match_etags | ActionDispatch::Request#if_none_match_etags |
249+
| action_controller/input_access.rb:25:5:25:29 | call to content_mime_type | ActionDispatch::Request#content_mime_type |
250+
| action_controller/input_access.rb:27:5:27:21 | call to authority | ActionDispatch::Request#authority |
251+
| action_controller/input_access.rb:28:5:28:16 | call to host | ActionDispatch::Request#host |
252+
| action_controller/input_access.rb:29:5:29:26 | call to host_authority | ActionDispatch::Request#host_authority |
253+
| action_controller/input_access.rb:30:5:30:26 | call to host_with_port | ActionDispatch::Request#host_with_port |
254+
| action_controller/input_access.rb:31:5:31:20 | call to hostname | ActionDispatch::Request#hostname |
255+
| action_controller/input_access.rb:32:5:32:25 | call to forwarded_for | ActionDispatch::Request#forwarded_for |
256+
| action_controller/input_access.rb:33:5:33:26 | call to forwarded_host | ActionDispatch::Request#forwarded_host |
257+
| action_controller/input_access.rb:34:5:34:16 | call to port | ActionDispatch::Request#port |
258+
| action_controller/input_access.rb:35:5:35:26 | call to forwarded_port | ActionDispatch::Request#forwarded_port |
259+
| action_controller/input_access.rb:37:5:37:22 | call to media_type | ActionDispatch::Request#media_type |
260+
| action_controller/input_access.rb:38:5:38:29 | call to media_type_params | ActionDispatch::Request#media_type_params |
261+
| action_controller/input_access.rb:39:5:39:27 | call to content_charset | ActionDispatch::Request#content_charset |
262+
| action_controller/input_access.rb:40:5:40:20 | call to base_url | ActionDispatch::Request#base_url |
263+
| action_controller/input_access.rb:42:5:42:16 | call to body | ActionDispatch::Request#body |
264+
| action_controller/input_access.rb:43:5:43:20 | call to raw_post | ActionDispatch::Request#raw_post |
265+
| action_controller/input_access.rb:45:5:45:30 | ...[...] | ActionDispatch::Request#env[] |
266+
| action_controller/input_access.rb:47:5:47:39 | ...[...] | ActionDispatch::Request#env[] |
226267
| action_controller/params_flow.rb:3:10:3:15 | call to params | ActionController::Metal#params |
227268
| action_controller/params_flow.rb:7:10:7:15 | call to params | ActionController::Metal#params |
228269
| action_controller/params_flow.rb:11:10:11:15 | call to params | ActionController::Metal#params |
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
class UsersController < ActionController::Base
2+
def index
3+
request.params
4+
request.parameters
5+
request.GET
6+
request.POST
7+
request.query_parameters
8+
request.request_parameters
9+
request.filtered_parameters
10+
11+
request.authorization
12+
request.script_name
13+
request.path_info
14+
request.user_agent
15+
request.referer
16+
request.referrer
17+
request.host_authority
18+
request.content_type
19+
request.host
20+
request.hostname
21+
request.accept_encoding
22+
request.accept_language
23+
request.if_none_match
24+
request.if_none_match_etags
25+
request.content_mime_type
26+
27+
request.authority
28+
request.host
29+
request.host_authority
30+
request.host_with_port
31+
request.hostname
32+
request.forwarded_for
33+
request.forwarded_host
34+
request.port
35+
request.forwarded_port
36+
37+
request.media_type
38+
request.media_type_params
39+
request.content_charset
40+
request.base_url
41+
42+
request.body
43+
request.raw_post
44+
45+
request.env["HTTP_ACCEPT"]
46+
request.env["NOT_USER_CONTROLLED"]
47+
request.filtered_env["HTTP_ACCEPT"]
48+
request.filtered_env["NOT_USER_CONTROLLED"]
49+
end
50+
end

0 commit comments

Comments
 (0)