brakeman 3.1.4 → 3.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES +19 -0
- data/README.md +3 -2
- data/lib/brakeman/app_tree.rb +58 -5
- data/lib/brakeman/checks/base_check.rb +13 -5
- data/lib/brakeman/checks/check_basic_auth_timing_attack.rb +54 -0
- data/lib/brakeman/checks/check_cross_site_scripting.rb +10 -4
- data/lib/brakeman/checks/check_dynamic_finders.rb +49 -0
- data/lib/brakeman/checks/check_mime_type_dos.rb +39 -0
- data/lib/brakeman/checks/check_nested_attributes_bypass.rb +58 -0
- data/lib/brakeman/checks/check_render.rb +24 -2
- data/lib/brakeman/checks/check_route_dos.rb +42 -0
- data/lib/brakeman/checks/check_sanitize_methods.rb +26 -4
- data/lib/brakeman/checks/check_sql.rb +5 -3
- data/lib/brakeman/checks/check_strip_tags.rb +27 -2
- data/lib/brakeman/options.rb +8 -2
- data/lib/brakeman/processors/alias_processor.rb +13 -0
- data/lib/brakeman/processors/controller_processor.rb +2 -2
- data/lib/brakeman/processors/lib/route_helper.rb +4 -0
- data/lib/brakeman/processors/model_processor.rb +2 -2
- data/lib/brakeman/scanner.rb +7 -2
- data/lib/brakeman/tracker/config.rb +6 -0
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning_codes.rb +9 -0
- metadata +7 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 449a20c68813d646031a349e4ef3144c387462f1
|
|
4
|
+
data.tar.gz: 65f2ed189a51bfc5e9b3d7bbe0d04d7fdfc8ae39
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fe400de4fdfe2d81dc1dfab9e5ff9f0b6f8c53f4c30f868b8e605185e74a907b2932ab3dbe5b793425fd90c5e55fb3f34efdd7d755f04223939ba38d4e5bb3ef
|
|
7
|
+
data.tar.gz: 1a7e2f419f4c8a2fdfc438406700220b2aba13409a5371db909a571d7a51bde96b1a231fbcd12d19fce49b463288b4d65100d35ba7e4879ed8fd04b729a037a7
|
data/CHANGES
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
# 3.1.5
|
|
2
|
+
|
|
3
|
+
* Fix CodeClimate construction of --only-files (Will Fleming)
|
|
4
|
+
* Add check for denial of service via routes (CVE-2015-7581)
|
|
5
|
+
* Warn about RCE with `render params` (CVE-2016-0752)
|
|
6
|
+
* Add check for `strip_tags` XSS (CVE-2015-7579)
|
|
7
|
+
* Add check for `sanitize` XSS (CVE-2015-7578/80)
|
|
8
|
+
* Add check for `reject_if` proc bypass (CVE-2015-7577)
|
|
9
|
+
* Add check for mime-type denial of service (CVE-2016-0751)
|
|
10
|
+
* Add check for basic auth timing attack (CVE-2015-7576)
|
|
11
|
+
* Add initial Rails 5 support
|
|
12
|
+
* Check for implict integer comparison in dynamic finders
|
|
13
|
+
* Support directories better in --only-files and --skip-files (Patrick Toomey)
|
|
14
|
+
* Avoid warning about `permit` in SQL
|
|
15
|
+
* Handle guards using `detect`
|
|
16
|
+
* Avoid warning on user input in comparisons
|
|
17
|
+
* Handle module names with self methods
|
|
18
|
+
* Add session manipulation documentation
|
|
19
|
+
|
|
1
20
|
# 3.1.4
|
|
2
21
|
|
|
3
22
|
* Emit brakeman's native fingerprints for Code Climate engine (Noah Davis)
|
data/README.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
[](https://travis-ci.org/presidentbeef/brakeman)
|
|
4
4
|
[](https://codeclimate.com/github/presidentbeef/brakeman)
|
|
5
5
|
[](https://codeclimate.com/github/presidentbeef/brakeman/coverage)
|
|
6
|
+
[](https://gitter.im/presidentbeef/brakeman)
|
|
6
7
|
|
|
7
8
|
# Brakeman
|
|
8
9
|
|
|
@@ -82,9 +83,9 @@ By default, Brakeman will return 0 as an exit code unless something went very wr
|
|
|
82
83
|
|
|
83
84
|
brakeman -z
|
|
84
85
|
|
|
85
|
-
To skip certain files that Brakeman may have trouble parsing, use:
|
|
86
|
+
To skip certain files or directories that Brakeman may have trouble parsing, use:
|
|
86
87
|
|
|
87
|
-
brakeman --skip-files file1
|
|
88
|
+
brakeman --skip-files file1,/path1/,path2/
|
|
88
89
|
|
|
89
90
|
To compare results of a scan with a previous scan, use the JSON output option and then:
|
|
90
91
|
|
data/lib/brakeman/app_tree.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'pathname'
|
|
2
|
+
|
|
1
3
|
module Brakeman
|
|
2
4
|
class AppTree
|
|
3
5
|
VIEW_EXTENSIONS = %w[html.erb html.haml rhtml js.erb html.slim].join(",")
|
|
@@ -10,15 +12,45 @@ module Brakeman
|
|
|
10
12
|
# Convert files into Regexp for matching
|
|
11
13
|
init_options = {}
|
|
12
14
|
if options[:skip_files]
|
|
13
|
-
init_options[:skip_files] =
|
|
15
|
+
init_options[:skip_files] = regex_for_paths(options[:skip_files])
|
|
14
16
|
end
|
|
17
|
+
|
|
15
18
|
if options[:only_files]
|
|
16
|
-
init_options[:only_files] =
|
|
19
|
+
init_options[:only_files] = regex_for_paths(options[:only_files])
|
|
17
20
|
end
|
|
18
21
|
init_options[:additional_libs_path] = options[:additional_libs_path]
|
|
19
22
|
new(root, init_options)
|
|
20
23
|
end
|
|
21
24
|
|
|
25
|
+
# Accepts an array of filenames and paths with the following format and
|
|
26
|
+
# returns a Regexp to match them:
|
|
27
|
+
# * "path1/file1.rb" - Matches a specific filename in the project directory.
|
|
28
|
+
# * "path1/" - Matches any path that conatains "path1" in the project directory.
|
|
29
|
+
# * "/path1/ - Matches any path that is rooted at "path1" in the project directory.
|
|
30
|
+
#
|
|
31
|
+
def self.regex_for_paths(paths)
|
|
32
|
+
path_regexes = paths.map do |f|
|
|
33
|
+
# If path ends in a file separator then we assume it is a path rather
|
|
34
|
+
# than a filename.
|
|
35
|
+
if f.end_with?(File::SEPARATOR)
|
|
36
|
+
# If path starts with a file separator then we assume that they
|
|
37
|
+
# want the project relative path to start with this path prefix.
|
|
38
|
+
if f.start_with?(File::SEPARATOR)
|
|
39
|
+
"\\A#{Regexp.escape f}"
|
|
40
|
+
# If it ends in a file separator, but does not begin with a file
|
|
41
|
+
# separator then we assume the path can match any path component in
|
|
42
|
+
# the project.
|
|
43
|
+
else
|
|
44
|
+
Regexp.escape f
|
|
45
|
+
end
|
|
46
|
+
else
|
|
47
|
+
"#{Regexp.escape f}\\z"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
Regexp.new("(?:" << path_regexes.join("|") << ")")
|
|
51
|
+
end
|
|
52
|
+
private_class_method(:regex_for_paths)
|
|
53
|
+
|
|
22
54
|
def initialize(root, init_options = {})
|
|
23
55
|
@root = root
|
|
24
56
|
@skip_files = init_options[:skip_files]
|
|
@@ -96,13 +128,34 @@ module Brakeman
|
|
|
96
128
|
|
|
97
129
|
def select_only_files(paths)
|
|
98
130
|
return paths unless @only_files
|
|
99
|
-
|
|
131
|
+
project_root = Pathname.new(@root)
|
|
132
|
+
paths.select do |path|
|
|
133
|
+
absolute_path = Pathname.new(path)
|
|
134
|
+
# relative root never has a leading separator. But, we use a leading
|
|
135
|
+
# separator in a @skip_files entry to imply that a directory is
|
|
136
|
+
# "absolute" with respect to the project directory.
|
|
137
|
+
project_relative_path = File.join(
|
|
138
|
+
File::SEPARATOR,
|
|
139
|
+
absolute_path.relative_path_from(project_root).to_s
|
|
140
|
+
)
|
|
141
|
+
@only_files.match(project_relative_path)
|
|
142
|
+
end
|
|
100
143
|
end
|
|
101
144
|
|
|
102
145
|
def reject_skipped_files(paths)
|
|
103
146
|
return paths unless @skip_files
|
|
104
|
-
|
|
147
|
+
project_root = Pathname.new(@root)
|
|
148
|
+
paths.reject do |path|
|
|
149
|
+
absolute_path = Pathname.new(path)
|
|
150
|
+
# relative root never has a leading separator. But, we use a leading
|
|
151
|
+
# separator in a @skip_files entry to imply that a directory is
|
|
152
|
+
# "absolute" with respect to the project directory.
|
|
153
|
+
project_relative_path = File.join(
|
|
154
|
+
File::SEPARATOR,
|
|
155
|
+
absolute_path.relative_path_from(project_root).to_s
|
|
156
|
+
)
|
|
157
|
+
@skip_files.match(project_relative_path)
|
|
158
|
+
end
|
|
105
159
|
end
|
|
106
|
-
|
|
107
160
|
end
|
|
108
161
|
end
|
|
@@ -35,6 +35,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
35
35
|
@mass_assign_disabled = nil
|
|
36
36
|
@has_user_input = nil
|
|
37
37
|
@safe_input_attributes = Set[:to_i, :to_f, :arel_table, :id]
|
|
38
|
+
@comparison_ops = Set[:==, :!=, :>, :<, :>=, :<=]
|
|
38
39
|
end
|
|
39
40
|
|
|
40
41
|
#Add result to result list, which is used to check for duplicates
|
|
@@ -71,12 +72,14 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
71
72
|
|
|
72
73
|
#Process calls and check if they include user input
|
|
73
74
|
def process_call exp
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
unless @comparison_ops.include? exp.method
|
|
76
|
+
process exp.target if sexp? exp.target
|
|
77
|
+
process_call_args exp
|
|
78
|
+
end
|
|
76
79
|
|
|
77
80
|
target = exp.target
|
|
78
81
|
|
|
79
|
-
unless
|
|
82
|
+
unless always_safe_method? exp.method
|
|
80
83
|
if params? target
|
|
81
84
|
@has_user_input = Match.new(:params, exp)
|
|
82
85
|
elsif cookies? target
|
|
@@ -123,6 +126,11 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
123
126
|
|
|
124
127
|
private
|
|
125
128
|
|
|
129
|
+
def always_safe_method? meth
|
|
130
|
+
@safe_input_attributes.include? meth or
|
|
131
|
+
@comparison_ops.include? meth
|
|
132
|
+
end
|
|
133
|
+
|
|
126
134
|
#Report a warning
|
|
127
135
|
def warn options
|
|
128
136
|
extra_opts = { :check => self.class.to_s }
|
|
@@ -286,7 +294,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
286
294
|
def has_immediate_user_input? exp
|
|
287
295
|
if exp.nil?
|
|
288
296
|
false
|
|
289
|
-
elsif call? exp and not
|
|
297
|
+
elsif call? exp and not always_safe_method? exp.method
|
|
290
298
|
if params? exp
|
|
291
299
|
return Match.new(:params, exp)
|
|
292
300
|
elsif cookies? exp
|
|
@@ -345,7 +353,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
|
345
353
|
target = exp.target
|
|
346
354
|
method = exp.method
|
|
347
355
|
|
|
348
|
-
if
|
|
356
|
+
if always_safe_method? method
|
|
349
357
|
false
|
|
350
358
|
elsif call? target and not method.to_s[-1,1] == "?"
|
|
351
359
|
if has_immediate_model?(target, out)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require 'brakeman/checks/base_check'
|
|
2
|
+
|
|
3
|
+
class Brakeman::CheckBasicAuthTimingAttack < Brakeman::BaseCheck
|
|
4
|
+
Brakeman::Checks.add self
|
|
5
|
+
|
|
6
|
+
@description = "Check for timing attack in basic auth (CVE-2015-7576)"
|
|
7
|
+
|
|
8
|
+
def run_check
|
|
9
|
+
@upgrade = case
|
|
10
|
+
when version_between?("0.0.0", "3.2.22")
|
|
11
|
+
"3.2.22.1"
|
|
12
|
+
when version_between?("4.0.0", "4.1.14")
|
|
13
|
+
"4.1.14.1"
|
|
14
|
+
when version_between?("4.2.0", "4.2.5")
|
|
15
|
+
"4.2.5.1"
|
|
16
|
+
else
|
|
17
|
+
return
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
check_basic_auth_filter
|
|
21
|
+
check_basic_auth_call
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def check_basic_auth_filter
|
|
25
|
+
controllers = tracker.controllers.select do |name, c|
|
|
26
|
+
c.options[:http_basic_authenticate_with]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
Hash[controllers].each do |name, controller|
|
|
30
|
+
controller.options[:http_basic_authenticate_with].each do |call|
|
|
31
|
+
warn :controller => name,
|
|
32
|
+
:warning_type => "Timing Attack",
|
|
33
|
+
:warning_code => :CVE_2015_7576,
|
|
34
|
+
:message => "Basic authentication in Rails #{rails_version} is vulnerable to timing attacks. Upgrade to #@upgrade",
|
|
35
|
+
:code => call,
|
|
36
|
+
:confidence => CONFIDENCE[:high],
|
|
37
|
+
:file => controller.file,
|
|
38
|
+
:link => "https://groups.google.com/d/msg/rubyonrails-security/ANv0HDHEC3k/mt7wNGxbFQAJ"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def check_basic_auth_call
|
|
44
|
+
# This is relatively unusual, but found in the wild
|
|
45
|
+
tracker.find_call(target: nil, method: :http_basic_authenticate_with).each do |result|
|
|
46
|
+
warn :result => result,
|
|
47
|
+
:warning_type => "Timing Attack",
|
|
48
|
+
:warning_code => :CVE_2015_7576,
|
|
49
|
+
:message => "Basic authentication in Rails #{rails_version} is vulnerable to timing attacks. Upgrade to #@upgrade",
|
|
50
|
+
:confidence => CONFIDENCE[:high],
|
|
51
|
+
:link => "https://groups.google.com/d/msg/rubyonrails-security/ANv0HDHEC3k/mt7wNGxbFQAJ"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -281,7 +281,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
|
281
281
|
end
|
|
282
282
|
|
|
283
283
|
def setup
|
|
284
|
-
@ignore_methods = Set[:button_to, :check_box, :content_tag, :escapeHTML, :escape_once,
|
|
284
|
+
@ignore_methods = Set[:==, :!=, :button_to, :check_box, :content_tag, :escapeHTML, :escape_once,
|
|
285
285
|
:field_field, :fields_for, :h, :hidden_field,
|
|
286
286
|
:hidden_field, :hidden_field_tag, :image_tag, :label,
|
|
287
287
|
:link_to, :mail_to, :radio_button, :select,
|
|
@@ -300,17 +300,23 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
|
300
300
|
@ignore_methods << :auto_link
|
|
301
301
|
end
|
|
302
302
|
|
|
303
|
-
if version_between? "2.0.0", "2.3.14"
|
|
303
|
+
if version_between? "2.0.0", "2.3.14" or tracker.config.gem_version(:'rails-html-sanitizer') == '1.0.2'
|
|
304
304
|
@known_dangerous << :strip_tags
|
|
305
305
|
end
|
|
306
306
|
|
|
307
|
+
if tracker.config.has_gem? :'rails-html-sanitizer' and
|
|
308
|
+
version_between? "1.0.0", "1.0.2", tracker.config.gem_version(:'rails-html-sanitizer')
|
|
309
|
+
|
|
310
|
+
@known_dangerous << :sanitize
|
|
311
|
+
end
|
|
312
|
+
|
|
307
313
|
json_escape_on = false
|
|
308
314
|
initializers = tracker.check_initializers :ActiveSupport, :escape_html_entities_in_json=
|
|
309
315
|
initializers.each {|result| json_escape_on = true?(result.call.first_arg) }
|
|
310
316
|
|
|
311
317
|
if tracker.config.escape_html_entities_in_json?
|
|
312
318
|
json_escape_on = true
|
|
313
|
-
elsif version_between? "4.0.0", "
|
|
319
|
+
elsif version_between? "4.0.0", "9.9.9"
|
|
314
320
|
json_escape_on = true
|
|
315
321
|
end
|
|
316
322
|
|
|
@@ -370,7 +376,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
|
370
376
|
end
|
|
371
377
|
|
|
372
378
|
def safe_input_attribute? target, method
|
|
373
|
-
target and
|
|
379
|
+
target and always_safe_method? method
|
|
374
380
|
end
|
|
375
381
|
|
|
376
382
|
def boolean_method? method
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require 'brakeman/checks/base_check'
|
|
2
|
+
|
|
3
|
+
#This check looks for regexes that include user input.
|
|
4
|
+
class Brakeman::CheckDynamicFinders < Brakeman::BaseCheck
|
|
5
|
+
Brakeman::Checks.add self
|
|
6
|
+
|
|
7
|
+
@description = "Check unsafe usage of find_by_*"
|
|
8
|
+
|
|
9
|
+
def run_check
|
|
10
|
+
if tracker.config.has_gem? :mysql and version_between? '2.0.0', '4.1.99'
|
|
11
|
+
tracker.find_call(:method => /^find_by_/).each do |result|
|
|
12
|
+
process_result result
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def process_result result
|
|
18
|
+
return if duplicate? result or result[:call].original_line
|
|
19
|
+
add_result result
|
|
20
|
+
|
|
21
|
+
call = result[:call]
|
|
22
|
+
|
|
23
|
+
if potentially_dangerous? call.method
|
|
24
|
+
call.each_arg do |arg|
|
|
25
|
+
if params? arg and not safe_call? arg
|
|
26
|
+
warn :result => result,
|
|
27
|
+
:warning_type => "SQL Injection",
|
|
28
|
+
:warning_code => :sql_injection_dynamic_finder,
|
|
29
|
+
:message => "MySQL integer conversion may cause 0 to match any string",
|
|
30
|
+
:confidence => CONFIDENCE[:med],
|
|
31
|
+
:user_input => arg
|
|
32
|
+
|
|
33
|
+
break
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def safe_call? arg
|
|
40
|
+
return false unless call? arg
|
|
41
|
+
|
|
42
|
+
meth = arg.method
|
|
43
|
+
meth == :to_s or meth == :to_i
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def potentially_dangerous? method_name
|
|
47
|
+
method_name.match /^find_by_.*(token|guid|password|api_key|activation|code|private|reset)/
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'brakeman/checks/base_check'
|
|
2
|
+
|
|
3
|
+
class Brakeman::CheckMimeTypeDoS < Brakeman::BaseCheck
|
|
4
|
+
Brakeman::Checks.add self
|
|
5
|
+
|
|
6
|
+
@description = "Checks for mime type denial of service (CVE-2016-0751)"
|
|
7
|
+
|
|
8
|
+
def run_check
|
|
9
|
+
fix_version = case
|
|
10
|
+
when version_between?("3.0.0", "3.2.22")
|
|
11
|
+
"3.2.22.1"
|
|
12
|
+
when version_between?("4.0.0", "4.1.14")
|
|
13
|
+
"4.1.14.1"
|
|
14
|
+
when version_between?("4.2.0", "4.2.5")
|
|
15
|
+
"4.2.5.1"
|
|
16
|
+
else
|
|
17
|
+
return
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
return if has_workaround?
|
|
21
|
+
|
|
22
|
+
message = "Rails #{rails_version} is vulnerable to denial of service via mime type caching (CVE-2016-0751). Upgrade to Rails version #{fix_version}"
|
|
23
|
+
|
|
24
|
+
warn :warning_type => "Denial of Service",
|
|
25
|
+
:warning_code => :CVE_2016_0751,
|
|
26
|
+
:message => message,
|
|
27
|
+
:confidence => CONFIDENCE[:med],
|
|
28
|
+
:gem_info => gemfile_or_environment,
|
|
29
|
+
:link_path => "https://groups.google.com/d/msg/rubyonrails-security/9oLY_FCzvoc/w9oI9XxbFQAJ"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def has_workaround?
|
|
33
|
+
tracker.check_initializers(:Mime, :const_set).any? do |match|
|
|
34
|
+
arg = match.call.first_arg
|
|
35
|
+
|
|
36
|
+
symbol? arg and arg.value == :LOOKUP
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require 'brakeman/checks/base_check'
|
|
2
|
+
|
|
3
|
+
#https://groups.google.com/d/msg/rubyonrails-security/cawsWcQ6c8g/tegZtYdbFQAJ
|
|
4
|
+
class Brakeman::CheckNestedAttributesBypass < Brakeman::BaseCheck
|
|
5
|
+
Brakeman::Checks.add self
|
|
6
|
+
|
|
7
|
+
@description = "Checks for nested attributes vulnerability (CVE-2015-7577)"
|
|
8
|
+
|
|
9
|
+
def run_check
|
|
10
|
+
if version_between? "3.1.0", "3.2.22" or
|
|
11
|
+
version_between? "4.0.0", "4.1.14" or
|
|
12
|
+
version_between? "4.2.0", "4.2.5"
|
|
13
|
+
|
|
14
|
+
unless workaround?
|
|
15
|
+
check_nested_attributes
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def check_nested_attributes
|
|
21
|
+
active_record_models.each do |name, model|
|
|
22
|
+
if opts = model.options[:accepts_nested_attributes_for]
|
|
23
|
+
opts.each do |args|
|
|
24
|
+
if args.any? { |a| allow_destroy? a } and args.any? { |a| reject_if? a }
|
|
25
|
+
warn_about_nested_attributes name, model, args
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def warn_about_nested_attributes name, model, args
|
|
33
|
+
message = "Rails #{rails_version} does not call :reject_if option when :allow_destroy is false (CVE-2015-7577)"
|
|
34
|
+
|
|
35
|
+
warn :model => name,
|
|
36
|
+
:warning_type => "Nested Attributes",
|
|
37
|
+
:warning_code => :CVE_2015_7577,
|
|
38
|
+
:message => message,
|
|
39
|
+
:file => model.file,
|
|
40
|
+
:line => args.line,
|
|
41
|
+
:confidence => CONFIDENCE[:med],
|
|
42
|
+
:link_path => "https://groups.google.com/d/msg/rubyonrails-security/cawsWcQ6c8g/tegZtYdbFQAJ"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def allow_destroy? arg
|
|
46
|
+
hash? arg and
|
|
47
|
+
false? hash_access(arg, :allow_destroy)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def reject_if? arg
|
|
51
|
+
hash? arg and
|
|
52
|
+
hash_access(arg, :reject_if)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def workaround?
|
|
56
|
+
tracker.check_initializers([], :will_be_destroyed?).any?
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -4,7 +4,7 @@ require 'brakeman/checks/base_check'
|
|
|
4
4
|
class Brakeman::CheckRender < Brakeman::BaseCheck
|
|
5
5
|
Brakeman::Checks.add self
|
|
6
6
|
|
|
7
|
-
@description = "Finds calls to render that might allow file access"
|
|
7
|
+
@description = "Finds calls to render that might allow file access or code execution"
|
|
8
8
|
|
|
9
9
|
def run_check
|
|
10
10
|
tracker.find_call(:target => nil, :method => :render).each do |result|
|
|
@@ -17,7 +17,8 @@ class Brakeman::CheckRender < Brakeman::BaseCheck
|
|
|
17
17
|
|
|
18
18
|
case result[:call].render_type
|
|
19
19
|
when :partial, :template, :action, :file
|
|
20
|
-
|
|
20
|
+
check_for_rce(result) or
|
|
21
|
+
check_for_dynamic_path(result)
|
|
21
22
|
when :inline
|
|
22
23
|
when :js
|
|
23
24
|
when :json
|
|
@@ -59,4 +60,25 @@ class Brakeman::CheckRender < Brakeman::BaseCheck
|
|
|
59
60
|
:confidence => confidence
|
|
60
61
|
end
|
|
61
62
|
end
|
|
63
|
+
|
|
64
|
+
def check_for_rce result
|
|
65
|
+
return unless version_between? "0.0.0", "3.2.22" or
|
|
66
|
+
version_between? "4.0.0", "4.1.14" or
|
|
67
|
+
version_between? "4.2.0", "4.2.5"
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
view = result[:call][2]
|
|
71
|
+
if sexp? view and not duplicate? result
|
|
72
|
+
if params? view
|
|
73
|
+
add_result result
|
|
74
|
+
|
|
75
|
+
warn :result => result,
|
|
76
|
+
:warning_type => "Remote Code Execution",
|
|
77
|
+
:warning_code => :dynamic_render_path_rce,
|
|
78
|
+
:message => "Passing query parameters to render() is vulnerable in Rails #{rails_version} (CVE-2016-0752)",
|
|
79
|
+
:user_input => view,
|
|
80
|
+
:confidence => CONFIDENCE[:high]
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
62
84
|
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require 'brakeman/checks/base_check'
|
|
2
|
+
|
|
3
|
+
class Brakeman::CheckRouteDoS < Brakeman::BaseCheck
|
|
4
|
+
Brakeman::Checks.add self
|
|
5
|
+
|
|
6
|
+
@description = "Checks for route DoS (CVE-2015-7581)"
|
|
7
|
+
|
|
8
|
+
def run_check
|
|
9
|
+
fix_version = case
|
|
10
|
+
when version_between?("4.0.0", "4.1.14")
|
|
11
|
+
"4.1.14.1"
|
|
12
|
+
when version_between?("4.2.0", "4.2.5")
|
|
13
|
+
"4.2.5.1"
|
|
14
|
+
else
|
|
15
|
+
return
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
if controller_wildcards?
|
|
19
|
+
message = "Rails #{rails_version} has a denial of service vulnerability with :controller routes (CVE-2015-7581). Upgrade to Rails #{fix_version}"
|
|
20
|
+
|
|
21
|
+
warn :warning_type => "Denial of Service",
|
|
22
|
+
:warning_code => :CVE_2015_7581,
|
|
23
|
+
:message => message,
|
|
24
|
+
:confidence => CONFIDENCE[:med],
|
|
25
|
+
:gem_info => gemfile_or_environment,
|
|
26
|
+
:link_path => "https://groups.google.com/d/msg/rubyonrails-security/dthJ5wL69JE/YzPnFelbFQAJ"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def controller_wildcards?
|
|
31
|
+
tracker.routes.each do |name, actions|
|
|
32
|
+
if name == :':controllerController'
|
|
33
|
+
# awful hack for routes with :controller in them
|
|
34
|
+
return true
|
|
35
|
+
elsif string? actions and actions.value.include? ":controller"
|
|
36
|
+
return true
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
false
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -17,12 +17,17 @@ class Brakeman::CheckSanitizeMethods < Brakeman::BaseCheck
|
|
|
17
17
|
'3.1.12'
|
|
18
18
|
when version_between?('3.2.0', '3.2.12')
|
|
19
19
|
'3.2.13'
|
|
20
|
-
else
|
|
21
|
-
return
|
|
22
20
|
end
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
if @fix_version
|
|
23
|
+
check_cve_2013_1855
|
|
24
|
+
check_cve_2013_1857
|
|
25
|
+
elsif tracker.config.has_gem? :'rails-html-sanitizer' and
|
|
26
|
+
version_between? "1.0.0", "1.0.2", tracker.config.gem_version(:'rails-html-sanitizer')
|
|
27
|
+
|
|
28
|
+
warn_sanitizer_cve "CVE-2015-7578", "https://groups.google.com/d/msg/rubyonrails-security/uh--W4TDwmI/JbvSRpdbFQAJ"
|
|
29
|
+
warn_sanitizer_cve "CVE-2015-7580", "https://groups.google.com/d/msg/rubyonrails-security/uh--W4TDwmI/m_CVZtdbFQAJ"
|
|
30
|
+
end
|
|
26
31
|
end
|
|
27
32
|
|
|
28
33
|
def check_cve_2013_1855
|
|
@@ -54,4 +59,21 @@ class Brakeman::CheckSanitizeMethods < Brakeman::BaseCheck
|
|
|
54
59
|
:link_path => link
|
|
55
60
|
end
|
|
56
61
|
end
|
|
62
|
+
|
|
63
|
+
def warn_sanitizer_cve cve, link
|
|
64
|
+
message = "rails-html-sanitizer #{tracker.config.gem_version(:'rails-html-sanitizer')} is vulnerable (#{cve}). Upgrade to 1.0.3"
|
|
65
|
+
|
|
66
|
+
if tracker.find_call(:target => false, :method => :sanitize).any?
|
|
67
|
+
confidence = CONFIDENCE[:high]
|
|
68
|
+
else
|
|
69
|
+
confidence = CONFIDENCE[:med]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
warn :warning_type => "Cross Site Scripting",
|
|
73
|
+
:warning_code => cve.tr('-', '_').to_sym,
|
|
74
|
+
:message => message,
|
|
75
|
+
:gem_info => gemfile_or_environment,
|
|
76
|
+
:confidence => confidence,
|
|
77
|
+
:link_path => link
|
|
78
|
+
end
|
|
57
79
|
end
|
|
@@ -59,7 +59,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
|
59
59
|
call = make_call(nil, :named_scope, args).line(args.line)
|
|
60
60
|
scope_calls << scope_call_hash(call, name, :named_scope)
|
|
61
61
|
end
|
|
62
|
-
elsif version_between?("3.1.0", "
|
|
62
|
+
elsif version_between?("3.1.0", "9.9.9")
|
|
63
63
|
ar_scope_calls(:scope) do |name, args|
|
|
64
64
|
second_arg = args[2]
|
|
65
65
|
next unless sexp? second_arg
|
|
@@ -264,8 +264,10 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
|
|
|
264
264
|
end
|
|
265
265
|
|
|
266
266
|
if request_value? arg
|
|
267
|
-
|
|
268
|
-
|
|
267
|
+
unless call? arg and params? arg.target and arg.method == :permit
|
|
268
|
+
# Model.where(params[:where])
|
|
269
|
+
arg
|
|
270
|
+
end
|
|
269
271
|
elsif hash? arg
|
|
270
272
|
#This is generally going to be a hash of column names and values, which
|
|
271
273
|
#would escape the values. But the keys _could_ be user input.
|
|
@@ -5,16 +5,21 @@ require 'brakeman/checks/base_check'
|
|
|
5
5
|
#
|
|
6
6
|
#Check for uses of strip_tags in Rails versions before 2.3.13 and 3.0.10:
|
|
7
7
|
#http://groups.google.com/group/rubyonrails-security/browse_thread/thread/2b9130749b74ea12
|
|
8
|
+
#
|
|
9
|
+
#Check for user of strip_tags with rails-html-sanitizer 1.0.2:
|
|
10
|
+
#https://groups.google.com/d/msg/rubyonrails-security/OU9ugTZcbjc/PjEP46pbFQAJ
|
|
8
11
|
class Brakeman::CheckStripTags < Brakeman::BaseCheck
|
|
9
12
|
Brakeman::Checks.add self
|
|
10
13
|
|
|
11
|
-
@description = "Report strip_tags vulnerabilities
|
|
14
|
+
@description = "Report strip_tags vulnerabilities"
|
|
12
15
|
|
|
13
16
|
def run_check
|
|
14
17
|
if uses_strip_tags?
|
|
15
18
|
cve_2011_2931
|
|
16
19
|
cve_2012_3465
|
|
17
20
|
end
|
|
21
|
+
|
|
22
|
+
cve_2015_7579
|
|
18
23
|
end
|
|
19
24
|
|
|
20
25
|
def cve_2011_2931
|
|
@@ -56,9 +61,29 @@ class Brakeman::CheckStripTags < Brakeman::BaseCheck
|
|
|
56
61
|
:link_path => "https://groups.google.com/d/topic/rubyonrails-security/FgVEtBajcTY/discussion"
|
|
57
62
|
end
|
|
58
63
|
|
|
64
|
+
def cve_2015_7579
|
|
65
|
+
if tracker.config.gem_version(:'rails-html-sanitizer') == '1.0.2'
|
|
66
|
+
if uses_strip_tags?
|
|
67
|
+
confidence = CONFIDENCE[:high]
|
|
68
|
+
else
|
|
69
|
+
confidence = CONFIDENCE[:med]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
message = "rails-html-sanitizer 1.0.2 is vulnerable (CVE-2015-7579). Upgrade to 1.0.3"
|
|
73
|
+
|
|
74
|
+
warn :warning_type => "Cross Site Scripting",
|
|
75
|
+
:warning_code => :CVE_2015_7579,
|
|
76
|
+
:message => message,
|
|
77
|
+
:confidence => confidence,
|
|
78
|
+
:gem_info => gemfile_or_environment,
|
|
79
|
+
:link_path => "https://groups.google.com/d/msg/rubyonrails-security/OU9ugTZcbjc/PjEP46pbFQAJ"
|
|
80
|
+
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
59
84
|
def uses_strip_tags?
|
|
60
85
|
Brakeman.debug "Finding calls to strip_tags()"
|
|
61
86
|
|
|
62
|
-
not tracker.find_call(:target => false, :method => :strip_tags).empty?
|
|
87
|
+
not tracker.find_call(:target => false, :method => :strip_tags, :nested => true).empty?
|
|
63
88
|
end
|
|
64
89
|
end
|
data/lib/brakeman/options.rb
CHANGED
|
@@ -52,6 +52,12 @@ module Brakeman::Options
|
|
|
52
52
|
options[:rails4] = true
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
opts.on "-5", "--rails5", "Force Rails 5 mode" do
|
|
56
|
+
options[:rails3] = true
|
|
57
|
+
options[:rails4] = true
|
|
58
|
+
options[:rails5] = true
|
|
59
|
+
end
|
|
60
|
+
|
|
55
61
|
opts.separator ""
|
|
56
62
|
opts.separator "Scanning options:"
|
|
57
63
|
|
|
@@ -110,12 +116,12 @@ module Brakeman::Options
|
|
|
110
116
|
options[:url_safe_methods].merge methods.map {|e| e.to_sym }
|
|
111
117
|
end
|
|
112
118
|
|
|
113
|
-
opts.on "--skip-files file1,
|
|
119
|
+
opts.on "--skip-files file1,path2,etc", Array, "Skip processing of these files/directories. Directories are application relative and must end in \"#{File::SEPARATOR}\"" do |files|
|
|
114
120
|
options[:skip_files] ||= Set.new
|
|
115
121
|
options[:skip_files].merge files
|
|
116
122
|
end
|
|
117
123
|
|
|
118
|
-
opts.on "--only-files file1,
|
|
124
|
+
opts.on "--only-files file1,path2,etc", Array, "Process only these files/directories. Directories are application relative and must end in \"#{File::SEPARATOR}\"" do |files|
|
|
119
125
|
options[:only_files] ||= Set.new
|
|
120
126
|
options[:only_files].merge files
|
|
121
127
|
end
|
|
@@ -212,6 +212,10 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
|
212
212
|
def process_iter exp
|
|
213
213
|
@exp_context.push exp
|
|
214
214
|
exp[1] = process exp.block_call
|
|
215
|
+
if array_detect_all_literals? exp[1]
|
|
216
|
+
return exp.block_call.target[1]
|
|
217
|
+
end
|
|
218
|
+
|
|
215
219
|
@exp_context.pop
|
|
216
220
|
|
|
217
221
|
env.scope do
|
|
@@ -524,6 +528,15 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
|
524
528
|
exp.target.all? { |e| e.is_a? Symbol or node_type? e, :lit, :str }
|
|
525
529
|
end
|
|
526
530
|
|
|
531
|
+
def array_detect_all_literals? exp
|
|
532
|
+
call? exp and
|
|
533
|
+
[:detect, :find].include? exp.method and
|
|
534
|
+
node_type? exp.target, :array and
|
|
535
|
+
exp.target.length > 1 and
|
|
536
|
+
exp.first_arg.nil? and
|
|
537
|
+
exp.target.all? { |e| e.is_a? Symbol or node_type? e, :lit, :str }
|
|
538
|
+
end
|
|
539
|
+
|
|
527
540
|
#Sets @inside_if = true
|
|
528
541
|
def process_if exp
|
|
529
542
|
if @ignore_ifs.nil?
|
|
@@ -208,11 +208,11 @@ class Brakeman::ControllerProcessor < Brakeman::BaseProcessor
|
|
|
208
208
|
def process_defs exp
|
|
209
209
|
name = exp.method_name
|
|
210
210
|
|
|
211
|
-
if exp[1]
|
|
211
|
+
if node_type? exp[1], :self
|
|
212
212
|
if @current_class
|
|
213
213
|
target = @current_class.name
|
|
214
214
|
elsif @current_module
|
|
215
|
-
target = @current_module
|
|
215
|
+
target = @current_module.name
|
|
216
216
|
else
|
|
217
217
|
target = nil
|
|
218
218
|
end
|
|
@@ -163,11 +163,11 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
|
|
|
163
163
|
return exp unless @current_class
|
|
164
164
|
name = exp.method_name
|
|
165
165
|
|
|
166
|
-
if exp[1]
|
|
166
|
+
if node_type? exp[1], :self
|
|
167
167
|
if @current_class
|
|
168
168
|
target = @current_class.name
|
|
169
169
|
elsif @current_module
|
|
170
|
-
target = @current_module
|
|
170
|
+
target = @current_module.name
|
|
171
171
|
else
|
|
172
172
|
target = nil
|
|
173
173
|
end
|
data/lib/brakeman/scanner.rb
CHANGED
|
@@ -96,7 +96,7 @@ class Brakeman::Scanner
|
|
|
96
96
|
#
|
|
97
97
|
#Stores parsed information in tracker.config
|
|
98
98
|
def process_config
|
|
99
|
-
if options[:rails3]
|
|
99
|
+
if options[:rails3] or options[:rails4] or options[:rails5]
|
|
100
100
|
process_config_file "application.rb"
|
|
101
101
|
process_config_file "environments/production.rb"
|
|
102
102
|
else
|
|
@@ -155,8 +155,13 @@ class Brakeman::Scanner
|
|
|
155
155
|
if @app_tree.exists?("script/rails")
|
|
156
156
|
tracker.options[:rails3] = true
|
|
157
157
|
Brakeman.notify "[Notice] Detected Rails 3 application"
|
|
158
|
+
elsif @app_tree.exists?("app/channels")
|
|
159
|
+
tracker.options[:rails3] = true
|
|
160
|
+
tracker.options[:rails4] = true
|
|
161
|
+
tracker.options[:rails5] = true
|
|
162
|
+
Brakeman.notify "[Notice] Detected Rails 5 application"
|
|
158
163
|
elsif not @app_tree.exists?("script")
|
|
159
|
-
tracker.options[:rails3] = true
|
|
164
|
+
tracker.options[:rails3] = true
|
|
160
165
|
tracker.options[:rails4] = true
|
|
161
166
|
Brakeman.notify "[Notice] Detected Rails 4 application"
|
|
162
167
|
end
|
|
@@ -7,6 +7,7 @@ module Brakeman
|
|
|
7
7
|
attr_reader :rails, :tracker
|
|
8
8
|
attr_accessor :rails_version
|
|
9
9
|
attr_writer :erubis, :escape_html
|
|
10
|
+
attr_reader :gems
|
|
10
11
|
|
|
11
12
|
def initialize tracker
|
|
12
13
|
@tracker = tracker
|
|
@@ -76,6 +77,11 @@ module Brakeman
|
|
|
76
77
|
tracker.options[:rails3] = true
|
|
77
78
|
tracker.options[:rails4] = true
|
|
78
79
|
Brakeman.notify "[Notice] Detected Rails 4 application"
|
|
80
|
+
elsif @rails_version.start_with? "5"
|
|
81
|
+
tracker.options[:rails3] = true
|
|
82
|
+
tracker.options[:rails4] = true
|
|
83
|
+
tracker.options[:rails5] = true
|
|
84
|
+
Brakeman.notify "[Notice] Detected Rails 5 application"
|
|
79
85
|
end
|
|
80
86
|
end
|
|
81
87
|
end
|
data/lib/brakeman/version.rb
CHANGED
|
@@ -93,6 +93,15 @@ module Brakeman::WarningCodes
|
|
|
93
93
|
:session_key_manipulation => 89,
|
|
94
94
|
:weak_hash_digest => 90,
|
|
95
95
|
:weak_hash_hmac => 91,
|
|
96
|
+
:sql_injection_dynamic_finder => 92,
|
|
97
|
+
:CVE_2015_7576 => 93,
|
|
98
|
+
:CVE_2016_0751 => 94,
|
|
99
|
+
:CVE_2015_7577 => 95,
|
|
100
|
+
:CVE_2015_7578 => 96,
|
|
101
|
+
:CVE_2015_7580 => 97,
|
|
102
|
+
:CVE_2015_7579 => 98,
|
|
103
|
+
:dynamic_render_path_rce => 99,
|
|
104
|
+
:CVE_2015_7581 => 100,
|
|
96
105
|
}
|
|
97
106
|
|
|
98
107
|
def self.code name
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: brakeman
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.1.
|
|
4
|
+
version: 3.1.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Justin Collins
|
|
@@ -9,7 +9,7 @@ autorequire:
|
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain:
|
|
11
11
|
- brakeman-public_cert.pem
|
|
12
|
-
date:
|
|
12
|
+
date: 2016-01-28 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: test-unit
|
|
@@ -223,6 +223,7 @@ files:
|
|
|
223
223
|
- lib/brakeman/checks.rb
|
|
224
224
|
- lib/brakeman/checks/base_check.rb
|
|
225
225
|
- lib/brakeman/checks/check_basic_auth.rb
|
|
226
|
+
- lib/brakeman/checks/check_basic_auth_timing_attack.rb
|
|
226
227
|
- lib/brakeman/checks/check_content_tag.rb
|
|
227
228
|
- lib/brakeman/checks/check_create_with.rb
|
|
228
229
|
- lib/brakeman/checks/check_cross_site_scripting.rb
|
|
@@ -230,6 +231,7 @@ files:
|
|
|
230
231
|
- lib/brakeman/checks/check_deserialize.rb
|
|
231
232
|
- lib/brakeman/checks/check_detailed_exceptions.rb
|
|
232
233
|
- lib/brakeman/checks/check_digest_dos.rb
|
|
234
|
+
- lib/brakeman/checks/check_dynamic_finders.rb
|
|
233
235
|
- lib/brakeman/checks/check_escape_function.rb
|
|
234
236
|
- lib/brakeman/checks/check_evaluation.rb
|
|
235
237
|
- lib/brakeman/checks/check_execute.rb
|
|
@@ -246,10 +248,12 @@ files:
|
|
|
246
248
|
- lib/brakeman/checks/check_link_to_href.rb
|
|
247
249
|
- lib/brakeman/checks/check_mail_to.rb
|
|
248
250
|
- lib/brakeman/checks/check_mass_assignment.rb
|
|
251
|
+
- lib/brakeman/checks/check_mime_type_dos.rb
|
|
249
252
|
- lib/brakeman/checks/check_model_attr_accessible.rb
|
|
250
253
|
- lib/brakeman/checks/check_model_attributes.rb
|
|
251
254
|
- lib/brakeman/checks/check_model_serialize.rb
|
|
252
255
|
- lib/brakeman/checks/check_nested_attributes.rb
|
|
256
|
+
- lib/brakeman/checks/check_nested_attributes_bypass.rb
|
|
253
257
|
- lib/brakeman/checks/check_number_to_currency.rb
|
|
254
258
|
- lib/brakeman/checks/check_quote_table_name.rb
|
|
255
259
|
- lib/brakeman/checks/check_redirect.rb
|
|
@@ -258,6 +262,7 @@ files:
|
|
|
258
262
|
- lib/brakeman/checks/check_render_dos.rb
|
|
259
263
|
- lib/brakeman/checks/check_render_inline.rb
|
|
260
264
|
- lib/brakeman/checks/check_response_splitting.rb
|
|
265
|
+
- lib/brakeman/checks/check_route_dos.rb
|
|
261
266
|
- lib/brakeman/checks/check_safe_buffer_manipulation.rb
|
|
262
267
|
- lib/brakeman/checks/check_sanitize_methods.rb
|
|
263
268
|
- lib/brakeman/checks/check_select_tag.rb
|