brakeman 3.0.5 → 3.1.0
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 -13
- data/lib/brakeman.rb +3 -0
- data/lib/brakeman/checks/base_check.rb +19 -47
- data/lib/brakeman/checks/check_basic_auth.rb +3 -3
- data/lib/brakeman/checks/check_cross_site_scripting.rb +26 -12
- data/lib/brakeman/checks/check_default_routes.rb +1 -1
- data/lib/brakeman/checks/check_detailed_exceptions.rb +2 -2
- data/lib/brakeman/checks/check_evaluation.rb +3 -0
- data/lib/brakeman/checks/check_execute.rb +3 -3
- data/lib/brakeman/checks/check_file_disclosure.rb +2 -2
- data/lib/brakeman/checks/check_forgery_setting.rb +9 -12
- data/lib/brakeman/checks/check_header_dos.rb +1 -1
- data/lib/brakeman/checks/check_i18n_xss.rb +2 -2
- data/lib/brakeman/checks/check_jruby_xml.rb +1 -1
- data/lib/brakeman/checks/check_json_encoding.rb +1 -1
- data/lib/brakeman/checks/check_json_parsing.rb +3 -3
- data/lib/brakeman/checks/check_link_to.rb +1 -1
- data/lib/brakeman/checks/check_link_to_href.rb +9 -2
- data/lib/brakeman/checks/check_mass_assignment.rb +5 -2
- data/lib/brakeman/checks/check_model_attr_accessible.rb +4 -4
- data/lib/brakeman/checks/check_model_attributes.rb +7 -7
- data/lib/brakeman/checks/check_model_serialize.rb +6 -6
- data/lib/brakeman/checks/check_nested_attributes.rb +2 -2
- data/lib/brakeman/checks/check_number_to_currency.rb +2 -2
- data/lib/brakeman/checks/check_quote_table_name.rb +1 -1
- data/lib/brakeman/checks/check_redirect.rb +2 -10
- data/lib/brakeman/checks/check_render.rb +1 -1
- data/lib/brakeman/checks/check_render_dos.rb +1 -1
- data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +1 -1
- data/lib/brakeman/checks/check_sanitize_methods.rb +1 -1
- data/lib/brakeman/checks/check_select_tag.rb +1 -1
- data/lib/brakeman/checks/check_select_vulnerability.rb +2 -2
- data/lib/brakeman/checks/check_session_settings.rb +1 -2
- data/lib/brakeman/checks/check_simple_format.rb +2 -2
- data/lib/brakeman/checks/check_single_quotes.rb +3 -3
- data/lib/brakeman/checks/check_skip_before_filter.rb +5 -7
- data/lib/brakeman/checks/check_sql.rb +10 -14
- data/lib/brakeman/checks/check_sql_cves.rb +4 -4
- data/lib/brakeman/checks/check_ssl_verify.rb +27 -9
- data/lib/brakeman/checks/check_strip_tags.rb +5 -5
- data/lib/brakeman/checks/check_symbol_dos_cve.rb +1 -1
- data/lib/brakeman/checks/check_translate_bug.rb +3 -4
- data/lib/brakeman/checks/check_unscoped_find.rb +1 -1
- data/lib/brakeman/checks/check_validation_regex.rb +2 -2
- data/lib/brakeman/checks/check_xml_dos.rb +1 -1
- data/lib/brakeman/checks/check_yaml_parsing.rb +1 -1
- data/lib/brakeman/file_parser.rb +1 -0
- data/lib/brakeman/parsers/template_parser.rb +6 -5
- data/lib/brakeman/processor.rb +7 -7
- data/lib/brakeman/processors/alias_processor.rb +30 -12
- data/lib/brakeman/processors/base_processor.rb +4 -8
- data/lib/brakeman/processors/controller_alias_processor.rb +33 -132
- data/lib/brakeman/processors/controller_processor.rb +29 -53
- data/lib/brakeman/processors/erb_template_processor.rb +4 -6
- data/lib/brakeman/processors/erubis_template_processor.rb +8 -11
- data/lib/brakeman/processors/gem_processor.rb +19 -35
- data/lib/brakeman/processors/haml_template_processor.rb +10 -12
- data/lib/brakeman/processors/lib/find_all_calls.rb +3 -5
- data/lib/brakeman/processors/lib/find_call.rb +2 -2
- data/lib/brakeman/processors/lib/find_return_value.rb +1 -1
- data/lib/brakeman/processors/lib/rails2_config_processor.rb +7 -8
- data/lib/brakeman/processors/lib/rails3_config_processor.rb +6 -7
- data/lib/brakeman/processors/lib/render_helper.rb +15 -14
- data/lib/brakeman/processors/lib/render_path.rb +11 -5
- data/lib/brakeman/processors/library_processor.rb +13 -35
- data/lib/brakeman/processors/model_processor.rb +22 -64
- data/lib/brakeman/processors/output_processor.rb +1 -37
- data/lib/brakeman/processors/slim_template_processor.rb +6 -8
- data/lib/brakeman/processors/template_alias_processor.rb +9 -9
- data/lib/brakeman/processors/template_processor.rb +5 -9
- data/lib/brakeman/report/report_base.rb +7 -7
- data/lib/brakeman/report/report_html.rb +5 -7
- data/lib/brakeman/report/report_markdown.rb +4 -6
- data/lib/brakeman/report/report_table.rb +4 -6
- data/lib/brakeman/rescanner.rb +29 -31
- data/lib/brakeman/scanner.rb +17 -8
- data/lib/brakeman/tracker.rb +24 -34
- data/lib/brakeman/tracker/collection.rb +77 -0
- data/lib/brakeman/tracker/config.rb +93 -0
- data/lib/brakeman/tracker/controller.rb +161 -0
- data/lib/brakeman/tracker/library.rb +17 -0
- data/lib/brakeman/tracker/model.rb +90 -0
- data/lib/brakeman/tracker/template.rb +33 -0
- data/lib/brakeman/util.rb +17 -9
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning.rb +8 -9
- data/lib/ruby_parser/bm_sexp.rb +16 -16
- data/lib/ruby_parser/bm_sexp_processor.rb +1 -120
- metadata +42 -31
- checksums.yaml.gz.sig +0 -1
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5db4cee0910ab76ab868345145436bbf8817ab04
|
4
|
+
data.tar.gz: 7633c66f5638aadb0ee5a1619755ee17e5a92ad0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 28a4089b017d8ee189a47b0597b18fa567637eb14d79caeea1beb1963ca17aa6761353d9ce557927516a5ec1d07b7e362c375b24e5893d84b1de5bc9041595cf
|
7
|
+
data.tar.gz: ea2a2b35fc4c7b6777cea07a9297bfcd32abe5ceaf476f7872efd845e8fcedb713ca91a128c31452ef148965945d1412d78c09c9c78cfe4e95aa24a5f07048c0
|
data/CHANGES
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
# 3.1.0
|
2
|
+
|
3
|
+
* Add support for gems.rb/gems.locked
|
4
|
+
* Update render path information in JSON reports
|
5
|
+
* Remove renaming of several Sexp nodes
|
6
|
+
* Convert YAML config keys to symbols (Karl Glaser)
|
7
|
+
* Use railties version if rails gem is missing (Lucas Mazza)
|
8
|
+
* Warn about unverified SSL mode in Net::HTTP.start
|
9
|
+
* Add Model, Controller, Template, Config classes internally
|
10
|
+
* Report file being parsed in debug output
|
11
|
+
* Update dependencies to Ruby 1.8 incompatible versions
|
12
|
+
* Treat Array.new and Hash.new as arrays/hashes
|
13
|
+
* Fix handling of string concatenation with existing string
|
14
|
+
* Treat html_safe like raw()
|
15
|
+
* Fix low confidence XSS warning code
|
16
|
+
* Avoid warning on path creation methods in link_to
|
17
|
+
* Expand safe methods to match methods with targets
|
18
|
+
* Avoid duplicate eval() warnings
|
19
|
+
|
1
20
|
# 3.0.5
|
2
21
|
|
3
22
|
* Fix check for CVE-2015-3227
|
data/README.md
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
[](http://brakemanscanner.org/)
|
2
2
|
|
3
|
-
[](https://codeclimate.com/github/presidentbeef/brakeman)
|
3
|
+
[](https://travis-ci.org/presidentbeef/brakeman)
|
4
|
+
[](https://codeclimate.com/github/presidentbeef/brakeman)
|
5
|
+
[](https://codeclimate.com/github/presidentbeef/brakeman/coverage)
|
7
6
|
|
8
7
|
# Brakeman
|
9
8
|
|
@@ -130,15 +129,6 @@ The default config locations are `./config/brakeman.yml`, `~/.brakeman/config.ym
|
|
130
129
|
|
131
130
|
The `-c` option can be used to specify a configuration file to use.
|
132
131
|
|
133
|
-
# For Slim Users
|
134
|
-
|
135
|
-
[Slim v3.0.0](https://github.com/slim-template/slim/blob/master/CHANGES#L12) dropped support for Ruby 1.8.7. Install a version of [`slim`](http://slim-lang.com/) compatible with your Ruby.
|
136
|
-
|
137
|
-
| Ruby Version | `Gemfile` | Command Line |
|
138
|
-
|--------------|-----------------------|----------------------------------------|
|
139
|
-
| Ruby 1.8.7 | `gem 'slim', '< 3.0'` | `$ gem install slim --version '< 3.0'` |
|
140
|
-
| Ruby 1.9+ | `gem 'slim'` | `$ gem install slim` |
|
141
|
-
|
142
132
|
# Continuous Integration
|
143
133
|
|
144
134
|
There is a [plugin available](http://brakemanscanner.org/docs/jenkins/) for Jenkins/Hudson.
|
data/lib/brakeman.rb
CHANGED
@@ -99,6 +99,9 @@ module Brakeman
|
|
99
99
|
|
100
100
|
if options
|
101
101
|
options.each { |k, v| options[k] = Set.new v if v.is_a? Array }
|
102
|
+
|
103
|
+
# After parsing the yaml config file for options, convert any string keys into symbols.
|
104
|
+
options.keys.select {|k| k.is_a? String}.map {|k| k.to_sym }.each {|k| options[k] = options[k.to_s]; options.delete(k.to_s) }
|
102
105
|
|
103
106
|
# notify if options[:quiet] and quiet is nil||false
|
104
107
|
notify "[Notice] Using configuration in #{config}" unless (options[:quiet] || quiet)
|
@@ -39,8 +39,9 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
39
39
|
|
40
40
|
#Add result to result list, which is used to check for duplicates
|
41
41
|
def add_result result, location = nil
|
42
|
-
location ||= (@current_template && @current_template
|
42
|
+
location ||= (@current_template && @current_template.name) || @current_class || @current_module || @current_set || result[:location][:class] || result[:location][:template]
|
43
43
|
location = location[:name] if location.is_a? Hash
|
44
|
+
location = location.name if location.is_a? Brakeman::Collection
|
44
45
|
location = location.to_sym
|
45
46
|
|
46
47
|
if result.is_a? Hash
|
@@ -115,7 +116,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
115
116
|
end
|
116
117
|
|
117
118
|
#Does not actually process string interpolation, but notes that it occurred.
|
118
|
-
def
|
119
|
+
def process_dstr exp
|
119
120
|
@string_interp = Match.new(:interp, exp)
|
120
121
|
process_default exp
|
121
122
|
end
|
@@ -138,36 +139,6 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
138
139
|
Brakeman::OutputProcessor.new.format(exp).gsub(/\r|\n/, "")
|
139
140
|
end
|
140
141
|
|
141
|
-
#Checks if the model inherits from parent,
|
142
|
-
def ancestor? model, parent, seen={}
|
143
|
-
return false unless model
|
144
|
-
|
145
|
-
seen[model[:name]] = true
|
146
|
-
if model[:parent] == parent || seen[model[:parent]]
|
147
|
-
true
|
148
|
-
elsif model[:parent]
|
149
|
-
ancestor? tracker.models[model[:parent]], parent, seen
|
150
|
-
else
|
151
|
-
false
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
def unprotected_model? model
|
156
|
-
model[:attr_accessible].nil? and !parent_classes_protected?(model) and ancestor?(model, :"ActiveRecord::Base")
|
157
|
-
end
|
158
|
-
|
159
|
-
# go up the chain of parent classes to see if any have attr_accessible
|
160
|
-
def parent_classes_protected? model, seen={}
|
161
|
-
seen[model] = true
|
162
|
-
if model[:attr_accessible] or model[:includes].include? :"ActiveModel::ForbiddenAttributesProtection"
|
163
|
-
true
|
164
|
-
elsif parent = tracker.models[model[:parent]] and !seen[parent]
|
165
|
-
parent_classes_protected? parent, seen
|
166
|
-
else
|
167
|
-
false
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
142
|
#Checks if mass assignment is disabled globally in an initializer.
|
172
143
|
def mass_assign_disabled?
|
173
144
|
return @mass_assign_disabled unless @mass_assign_disabled.nil?
|
@@ -175,12 +146,10 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
175
146
|
@mass_assign_disabled = false
|
176
147
|
|
177
148
|
if version_between?("3.1.0", "3.9.9") and
|
178
|
-
tracker.config
|
179
|
-
tracker.config[:rails][:active_record][:whitelist_attributes] == Sexp.new(:true)
|
149
|
+
tracker.config.whitelist_attributes?
|
180
150
|
|
181
151
|
@mass_assign_disabled = true
|
182
|
-
elsif tracker.options[:rails4] && (!tracker.config
|
183
|
-
tracker.config[:rails][:active_record][:whitelist_attributes] == Sexp.new(:true)))
|
152
|
+
elsif tracker.options[:rails4] && (!tracker.config.has_gem?(:protected_attributes) || tracker.config.whitelist_attributes?)
|
184
153
|
|
185
154
|
@mass_assign_disabled = true
|
186
155
|
else
|
@@ -231,7 +200,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
231
200
|
#gem and still using hack above, so this is a separate check for
|
232
201
|
#including ActiveModel::ForbiddenAttributesProtection in
|
233
202
|
#ActiveRecord::Base in an initializer.
|
234
|
-
if not @mass_assign_disabled and version_between?("3.1.0", "3.9.9") and tracker.config
|
203
|
+
if not @mass_assign_disabled and version_between?("3.1.0", "3.9.9") and tracker.config.has_gem? :strong_parameters
|
235
204
|
matches = tracker.check_initializers([], :include)
|
236
205
|
forbidden_protection = Sexp.new(:colon2, Sexp.new(:const, :ActiveModel), :ForbiddenAttributesProtection)
|
237
206
|
|
@@ -267,9 +236,10 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
267
236
|
raise ArgumentError
|
268
237
|
end
|
269
238
|
|
270
|
-
location ||= (@current_template && @current_template
|
239
|
+
location ||= (@current_template && @current_template.name) || @current_class || @current_module || @current_set || result[:location][:class] || result[:location][:template]
|
271
240
|
|
272
241
|
location = location[:name] if location.is_a? Hash
|
242
|
+
location = location.name if location.is_a? Brakeman::Collection
|
273
243
|
location = location.to_sym
|
274
244
|
|
275
245
|
@results.each do |r|
|
@@ -328,7 +298,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
328
298
|
end
|
329
299
|
elsif sexp? exp
|
330
300
|
case exp.node_type
|
331
|
-
when :
|
301
|
+
when :dstr
|
332
302
|
exp.each do |e|
|
333
303
|
if sexp? e
|
334
304
|
match = has_immediate_user_input?(e)
|
@@ -336,7 +306,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
336
306
|
end
|
337
307
|
end
|
338
308
|
false
|
339
|
-
when :
|
309
|
+
when :evstr
|
340
310
|
if sexp? exp.value
|
341
311
|
if exp.value.node_type == :rlist
|
342
312
|
exp.value.each_sexp do |e|
|
@@ -390,14 +360,14 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
390
360
|
end
|
391
361
|
elsif sexp? exp
|
392
362
|
case exp.node_type
|
393
|
-
when :
|
363
|
+
when :dstr
|
394
364
|
exp.each do |e|
|
395
365
|
if sexp? e and match = has_immediate_model?(e, out)
|
396
366
|
return match
|
397
367
|
end
|
398
368
|
end
|
399
369
|
false
|
400
|
-
when :
|
370
|
+
when :evstr
|
401
371
|
if sexp? exp.value
|
402
372
|
if exp.value.node_type == :rlist
|
403
373
|
exp.value.each_sexp do |e|
|
@@ -456,7 +426,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
456
426
|
#
|
457
427
|
#If the Rails version is unknown, returns false.
|
458
428
|
def version_between? low_version, high_version, current_version = nil
|
459
|
-
current_version ||=
|
429
|
+
current_version ||= rails_version
|
460
430
|
return false unless current_version
|
461
431
|
|
462
432
|
version = current_version.split(".").map! { |n| n.to_i }
|
@@ -483,15 +453,17 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
483
453
|
end
|
484
454
|
|
485
455
|
def lts_version? version
|
486
|
-
tracker.config
|
487
|
-
version_between? version, "2.3.18.99", tracker.config
|
456
|
+
tracker.config.has_gem? :'railslts-version' and
|
457
|
+
version_between? version, "2.3.18.99", tracker.config.gem_version(:'railslts-version')
|
488
458
|
end
|
489
459
|
|
490
460
|
def gemfile_or_environment gem_name = :rails
|
491
|
-
if gem_name and info = tracker.config
|
461
|
+
if gem_name and info = tracker.config.get_gem(gem_name)
|
492
462
|
info
|
493
463
|
elsif @app_tree.exists?("Gemfile")
|
494
464
|
"Gemfile"
|
465
|
+
elsif @app_tree.exists?("gems.rb")
|
466
|
+
"gems.rb"
|
495
467
|
else
|
496
468
|
"config/environment.rb"
|
497
469
|
end
|
@@ -507,7 +479,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
|
|
507
479
|
@active_record_models = {}
|
508
480
|
|
509
481
|
tracker.models.each do |name, model|
|
510
|
-
if ancestor?
|
482
|
+
if model.ancestor? :"ActiveRecord::Base"
|
511
483
|
@active_record_models[name] = model
|
512
484
|
end
|
513
485
|
end
|
@@ -18,11 +18,11 @@ class Brakeman::CheckBasicAuth < Brakeman::BaseCheck
|
|
18
18
|
|
19
19
|
def check_basic_auth_filter
|
20
20
|
controllers = tracker.controllers.select do |name, c|
|
21
|
-
c
|
21
|
+
c.options[:http_basic_authenticate_with]
|
22
22
|
end
|
23
23
|
|
24
24
|
Hash[controllers].each do |name, controller|
|
25
|
-
controller
|
25
|
+
controller.options[:http_basic_authenticate_with].each do |call|
|
26
26
|
|
27
27
|
if pass = get_password(call) and string? pass
|
28
28
|
warn :controller => name,
|
@@ -31,7 +31,7 @@ class Brakeman::CheckBasicAuth < Brakeman::BaseCheck
|
|
31
31
|
:message => "Basic authentication password stored in source code",
|
32
32
|
:code => call,
|
33
33
|
:confidence => 0,
|
34
|
-
:file => controller
|
34
|
+
:file => controller.file
|
35
35
|
break
|
36
36
|
end
|
37
37
|
end
|
@@ -42,7 +42,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
42
42
|
|
43
43
|
@current_template = template
|
44
44
|
|
45
|
-
template
|
45
|
+
template.each_output do |out|
|
46
46
|
unless check_for_immediate_xss out
|
47
47
|
@matched = false
|
48
48
|
@mark = false
|
@@ -57,10 +57,16 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
57
57
|
|
58
58
|
if exp.node_type == :output
|
59
59
|
out = exp.value
|
60
|
-
elsif exp.node_type == :escaped_output
|
61
|
-
|
60
|
+
elsif exp.node_type == :escaped_output
|
61
|
+
if raw_call? exp
|
62
|
+
out = exp.value.first_arg
|
63
|
+
elsif html_safe_call? exp
|
64
|
+
out = exp.value.target
|
65
|
+
end
|
62
66
|
end
|
63
67
|
|
68
|
+
return if call? out and ignore_call? out.target, out.method
|
69
|
+
|
64
70
|
if input = has_immediate_user_input?(out)
|
65
71
|
add_result exp
|
66
72
|
|
@@ -141,8 +147,12 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
141
147
|
#Otherwise, ignore
|
142
148
|
def process_escaped_output exp
|
143
149
|
unless check_for_immediate_xss exp
|
144
|
-
if
|
145
|
-
|
150
|
+
if not duplicate? exp
|
151
|
+
if raw_call? exp
|
152
|
+
process exp.value.first_arg
|
153
|
+
elsif html_safe_call? exp
|
154
|
+
process exp.value.target
|
155
|
+
end
|
146
156
|
end
|
147
157
|
end
|
148
158
|
exp
|
@@ -171,11 +181,14 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
171
181
|
add_result exp
|
172
182
|
|
173
183
|
link_path = "cross_site_scripting"
|
184
|
+
warning_code = :cross_site_scripting
|
185
|
+
|
174
186
|
if @known_dangerous.include? exp.method
|
175
187
|
confidence = CONFIDENCE[:high]
|
176
188
|
if exp.method == :to_json
|
177
189
|
message += " in JSON hash"
|
178
190
|
link_path += "_to_json"
|
191
|
+
warning_code = :xss_to_json
|
179
192
|
end
|
180
193
|
else
|
181
194
|
confidence = CONFIDENCE[:low]
|
@@ -183,7 +196,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
183
196
|
|
184
197
|
warn :template => @current_template,
|
185
198
|
:warning_type => "Cross Site Scripting",
|
186
|
-
:warning_code =>
|
199
|
+
:warning_code => warning_code,
|
187
200
|
:message => message,
|
188
201
|
:code => exp,
|
189
202
|
:user_input => @matched.match,
|
@@ -239,7 +252,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
239
252
|
end
|
240
253
|
|
241
254
|
#Process as default
|
242
|
-
def
|
255
|
+
def process_dstr exp
|
243
256
|
process_default exp
|
244
257
|
end
|
245
258
|
|
@@ -301,9 +314,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
301
314
|
initializers = tracker.check_initializers :ActiveSupport, :escape_html_entities_in_json=
|
302
315
|
initializers.each {|result| json_escape_on = true?(result.call.first_arg) }
|
303
316
|
|
304
|
-
if tracker.config
|
305
|
-
true? tracker.config[:rails][:active_support][:escape_html_entities_in_json]
|
306
|
-
|
317
|
+
if tracker.config.escape_html_entities_in_json?
|
307
318
|
json_escape_on = true
|
308
319
|
elsif version_between? "4.0.0", "5.0.0"
|
309
320
|
json_escape_on = true
|
@@ -322,6 +333,10 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
322
333
|
exp.value.node_type == :call and exp.value.method == :raw
|
323
334
|
end
|
324
335
|
|
336
|
+
def html_safe_call? exp
|
337
|
+
exp.value.node_type == :call and exp.value.method == :html_safe
|
338
|
+
end
|
339
|
+
|
325
340
|
def ignore_call? target, method
|
326
341
|
ignored_method?(target, method) or
|
327
342
|
safe_input_attribute?(target, method) or
|
@@ -340,8 +355,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
|
|
340
355
|
end
|
341
356
|
|
342
357
|
def ignored_method? target, method
|
343
|
-
|
344
|
-
(@ignore_methods.include? method or method.to_s =~ IGNORE_LIKE)
|
358
|
+
@ignore_methods.include? method or method.to_s =~ IGNORE_LIKE
|
345
359
|
end
|
346
360
|
|
347
361
|
def cgi_escaped? target, method
|
@@ -74,7 +74,7 @@ class Brakeman::CheckDefaultRoutes < Brakeman::BaseCheck
|
|
74
74
|
|
75
75
|
warn :warning_type => "Remote Code Execution",
|
76
76
|
:warning_code => :CVE_2014_0130,
|
77
|
-
:message => "Rails #{
|
77
|
+
:message => "Rails #{rails_version} with globbing routes is vulnerable to directory traversal and remote code execution. Patch or upgrade to #{upgrade}",
|
78
78
|
:confidence => confidence,
|
79
79
|
:file => "#{tracker.app_path}/config/routes.rb",
|
80
80
|
:link => "http://matasano.com/research/AnatomyOfRailsVuln-CVE-2014-0130.pdf"
|
@@ -14,7 +14,7 @@ class Brakeman::CheckDetailedExceptions < Brakeman::BaseCheck
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def check_local_request_config
|
17
|
-
if true? tracker.config
|
17
|
+
if true? tracker.config.rails[:consider_all_requests_local]
|
18
18
|
warn :warning_type => "Information Disclosure",
|
19
19
|
:warning_code => :local_request_config,
|
20
20
|
:message => "Detailed exceptions are enabled in production",
|
@@ -25,7 +25,7 @@ class Brakeman::CheckDetailedExceptions < Brakeman::BaseCheck
|
|
25
25
|
|
26
26
|
def check_detailed_exceptions
|
27
27
|
tracker.controllers.each do |name, controller|
|
28
|
-
controller
|
28
|
+
controller.methods_public.each do |name, definition|
|
29
29
|
src = definition[:src]
|
30
30
|
body = src.body.last
|
31
31
|
next unless body
|
@@ -20,6 +20,9 @@ class Brakeman::CheckEvaluation < Brakeman::BaseCheck
|
|
20
20
|
|
21
21
|
#Warns if eval includes user input
|
22
22
|
def process_result result
|
23
|
+
return if duplicate? result or result[:call].original_line
|
24
|
+
add_result result
|
25
|
+
|
23
26
|
if input = include_user_input?(result[:call].arglist)
|
24
27
|
warn :result => result,
|
25
28
|
:warning_type => "Dangerous Eval",
|
@@ -82,10 +82,10 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def dangerous_open_arg? exp
|
85
|
-
if
|
85
|
+
if string_interp? exp
|
86
86
|
# Check for input at start of string
|
87
87
|
exp[1] == "" and
|
88
|
-
node_type? exp[2], :evstr
|
88
|
+
node_type? exp[2], :evstr and
|
89
89
|
has_immediate_user_input? exp[2]
|
90
90
|
else
|
91
91
|
has_immediate_user_input? exp
|
@@ -137,7 +137,7 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
|
|
137
137
|
e = e.target
|
138
138
|
end
|
139
139
|
|
140
|
-
if node_type? e, :or, :evstr, :
|
140
|
+
if node_type? e, :or, :evstr, :dstr
|
141
141
|
if res = dangerous?(e)
|
142
142
|
return res
|
143
143
|
end
|
@@ -22,7 +22,7 @@ class Brakeman::CheckFileDisclosure < Brakeman::BaseCheck
|
|
22
22
|
if fix_version and serves_static_assets?
|
23
23
|
warn :warning_type => "File Access",
|
24
24
|
:warning_code => :CVE_2014_7829,
|
25
|
-
:message => "Rails #{
|
25
|
+
:message => "Rails #{rails_version} has a file existence disclosure. Upgrade to #{fix_version} or disable serving static assets",
|
26
26
|
:confidence => CONFIDENCE[:high],
|
27
27
|
:gem_info => gemfile_or_environment,
|
28
28
|
:link_path => "https://groups.google.com/d/msg/rubyonrails-security/23fiuwb1NBA/MQVM1-5GkPMJ"
|
@@ -30,6 +30,6 @@ class Brakeman::CheckFileDisclosure < Brakeman::BaseCheck
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def serves_static_assets?
|
33
|
-
true? tracker.config
|
33
|
+
true? tracker.config.rails[:serve_static_assets]
|
34
34
|
end
|
35
35
|
end
|
@@ -11,34 +11,31 @@ class Brakeman::CheckForgerySetting < Brakeman::BaseCheck
|
|
11
11
|
|
12
12
|
def run_check
|
13
13
|
app_controller = tracker.controllers[:ApplicationController]
|
14
|
+
return unless app_controller and app_controller.ancestor? :"ActionController::Base"
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
if tracker.config[:rails][:action_controller] and
|
18
|
-
tracker.config[:rails][:action_controller][:allow_forgery_protection] == Sexp.new(:false)
|
19
|
-
|
16
|
+
if tracker.config.allow_forgery_protection?
|
20
17
|
warn :controller => :ApplicationController,
|
21
18
|
:warning_type => "Cross-Site Request Forgery",
|
22
19
|
:warning_code => :csrf_protection_disabled,
|
23
20
|
:message => "Forgery protection is disabled",
|
24
21
|
:confidence => CONFIDENCE[:high],
|
25
|
-
:file => app_controller
|
22
|
+
:file => app_controller.file
|
26
23
|
|
27
|
-
elsif app_controller and not app_controller
|
24
|
+
elsif app_controller and not app_controller.protect_from_forgery?
|
28
25
|
|
29
26
|
warn :controller => :ApplicationController,
|
30
27
|
:warning_type => "Cross-Site Request Forgery",
|
31
28
|
:warning_code => :csrf_protection_missing,
|
32
29
|
:message => "'protect_from_forgery' should be called in ApplicationController",
|
33
30
|
:confidence => CONFIDENCE[:high],
|
34
|
-
:file => app_controller
|
31
|
+
:file => app_controller.file
|
35
32
|
|
36
33
|
elsif version_between? "2.1.0", "2.3.10"
|
37
34
|
|
38
35
|
warn :controller => :ApplicationController,
|
39
36
|
:warning_type => "Cross-Site Request Forgery",
|
40
37
|
:warning_code => :CVE_2011_0447,
|
41
|
-
:message => "CSRF protection is flawed in unpatched versions of Rails #{
|
38
|
+
:message => "CSRF protection is flawed in unpatched versions of Rails #{rails_version} (CVE-2011-0447). Upgrade to 2.3.11 or apply patches as needed",
|
42
39
|
:confidence => CONFIDENCE[:high],
|
43
40
|
:gem_info => gemfile_or_environment,
|
44
41
|
:link_path => "https://groups.google.com/d/topic/rubyonrails-security/LZWjzCPgNmU/discussion"
|
@@ -48,11 +45,11 @@ class Brakeman::CheckForgerySetting < Brakeman::BaseCheck
|
|
48
45
|
warn :controller => :ApplicationController,
|
49
46
|
:warning_type => "Cross-Site Request Forgery",
|
50
47
|
:warning_code => :CVE_2011_0447,
|
51
|
-
:message => "CSRF protection is flawed in unpatched versions of Rails #{
|
48
|
+
:message => "CSRF protection is flawed in unpatched versions of Rails #{rails_version} (CVE-2011-0447). Upgrade to 3.0.4 or apply patches as needed",
|
52
49
|
:confidence => CONFIDENCE[:high],
|
53
50
|
:gem_info => gemfile_or_environment,
|
54
51
|
:link_path => "https://groups.google.com/d/topic/rubyonrails-security/LZWjzCPgNmU/discussion"
|
55
|
-
elsif version_between? "4.0.0", "100.0.0" and forgery_opts = app_controller
|
52
|
+
elsif version_between? "4.0.0", "100.0.0" and forgery_opts = app_controller.options[:protect_from_forgery]
|
56
53
|
|
57
54
|
unless forgery_opts.is_a?(Array) and sexp?(forgery_opts.first) and
|
58
55
|
access_arg = hash_access(forgery_opts.first.first_arg, :with) and access_arg.value == :exception
|
@@ -63,7 +60,7 @@ class Brakeman::CheckForgerySetting < Brakeman::BaseCheck
|
|
63
60
|
:warning_code => :csrf_not_protected_by_raising_exception,
|
64
61
|
:message => "protect_from_forgery should be configured with 'with: :exception'",
|
65
62
|
:confidence => CONFIDENCE[:med],
|
66
|
-
:file => app_controller
|
63
|
+
:file => app_controller.file
|
67
64
|
}
|
68
65
|
|
69
66
|
args.merge!(:code => forgery_opts.first) if forgery_opts.is_a?(Array)
|