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.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +19 -0
  3. data/README.md +3 -13
  4. data/lib/brakeman.rb +3 -0
  5. data/lib/brakeman/checks/base_check.rb +19 -47
  6. data/lib/brakeman/checks/check_basic_auth.rb +3 -3
  7. data/lib/brakeman/checks/check_cross_site_scripting.rb +26 -12
  8. data/lib/brakeman/checks/check_default_routes.rb +1 -1
  9. data/lib/brakeman/checks/check_detailed_exceptions.rb +2 -2
  10. data/lib/brakeman/checks/check_evaluation.rb +3 -0
  11. data/lib/brakeman/checks/check_execute.rb +3 -3
  12. data/lib/brakeman/checks/check_file_disclosure.rb +2 -2
  13. data/lib/brakeman/checks/check_forgery_setting.rb +9 -12
  14. data/lib/brakeman/checks/check_header_dos.rb +1 -1
  15. data/lib/brakeman/checks/check_i18n_xss.rb +2 -2
  16. data/lib/brakeman/checks/check_jruby_xml.rb +1 -1
  17. data/lib/brakeman/checks/check_json_encoding.rb +1 -1
  18. data/lib/brakeman/checks/check_json_parsing.rb +3 -3
  19. data/lib/brakeman/checks/check_link_to.rb +1 -1
  20. data/lib/brakeman/checks/check_link_to_href.rb +9 -2
  21. data/lib/brakeman/checks/check_mass_assignment.rb +5 -2
  22. data/lib/brakeman/checks/check_model_attr_accessible.rb +4 -4
  23. data/lib/brakeman/checks/check_model_attributes.rb +7 -7
  24. data/lib/brakeman/checks/check_model_serialize.rb +6 -6
  25. data/lib/brakeman/checks/check_nested_attributes.rb +2 -2
  26. data/lib/brakeman/checks/check_number_to_currency.rb +2 -2
  27. data/lib/brakeman/checks/check_quote_table_name.rb +1 -1
  28. data/lib/brakeman/checks/check_redirect.rb +2 -10
  29. data/lib/brakeman/checks/check_render.rb +1 -1
  30. data/lib/brakeman/checks/check_render_dos.rb +1 -1
  31. data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +1 -1
  32. data/lib/brakeman/checks/check_sanitize_methods.rb +1 -1
  33. data/lib/brakeman/checks/check_select_tag.rb +1 -1
  34. data/lib/brakeman/checks/check_select_vulnerability.rb +2 -2
  35. data/lib/brakeman/checks/check_session_settings.rb +1 -2
  36. data/lib/brakeman/checks/check_simple_format.rb +2 -2
  37. data/lib/brakeman/checks/check_single_quotes.rb +3 -3
  38. data/lib/brakeman/checks/check_skip_before_filter.rb +5 -7
  39. data/lib/brakeman/checks/check_sql.rb +10 -14
  40. data/lib/brakeman/checks/check_sql_cves.rb +4 -4
  41. data/lib/brakeman/checks/check_ssl_verify.rb +27 -9
  42. data/lib/brakeman/checks/check_strip_tags.rb +5 -5
  43. data/lib/brakeman/checks/check_symbol_dos_cve.rb +1 -1
  44. data/lib/brakeman/checks/check_translate_bug.rb +3 -4
  45. data/lib/brakeman/checks/check_unscoped_find.rb +1 -1
  46. data/lib/brakeman/checks/check_validation_regex.rb +2 -2
  47. data/lib/brakeman/checks/check_xml_dos.rb +1 -1
  48. data/lib/brakeman/checks/check_yaml_parsing.rb +1 -1
  49. data/lib/brakeman/file_parser.rb +1 -0
  50. data/lib/brakeman/parsers/template_parser.rb +6 -5
  51. data/lib/brakeman/processor.rb +7 -7
  52. data/lib/brakeman/processors/alias_processor.rb +30 -12
  53. data/lib/brakeman/processors/base_processor.rb +4 -8
  54. data/lib/brakeman/processors/controller_alias_processor.rb +33 -132
  55. data/lib/brakeman/processors/controller_processor.rb +29 -53
  56. data/lib/brakeman/processors/erb_template_processor.rb +4 -6
  57. data/lib/brakeman/processors/erubis_template_processor.rb +8 -11
  58. data/lib/brakeman/processors/gem_processor.rb +19 -35
  59. data/lib/brakeman/processors/haml_template_processor.rb +10 -12
  60. data/lib/brakeman/processors/lib/find_all_calls.rb +3 -5
  61. data/lib/brakeman/processors/lib/find_call.rb +2 -2
  62. data/lib/brakeman/processors/lib/find_return_value.rb +1 -1
  63. data/lib/brakeman/processors/lib/rails2_config_processor.rb +7 -8
  64. data/lib/brakeman/processors/lib/rails3_config_processor.rb +6 -7
  65. data/lib/brakeman/processors/lib/render_helper.rb +15 -14
  66. data/lib/brakeman/processors/lib/render_path.rb +11 -5
  67. data/lib/brakeman/processors/library_processor.rb +13 -35
  68. data/lib/brakeman/processors/model_processor.rb +22 -64
  69. data/lib/brakeman/processors/output_processor.rb +1 -37
  70. data/lib/brakeman/processors/slim_template_processor.rb +6 -8
  71. data/lib/brakeman/processors/template_alias_processor.rb +9 -9
  72. data/lib/brakeman/processors/template_processor.rb +5 -9
  73. data/lib/brakeman/report/report_base.rb +7 -7
  74. data/lib/brakeman/report/report_html.rb +5 -7
  75. data/lib/brakeman/report/report_markdown.rb +4 -6
  76. data/lib/brakeman/report/report_table.rb +4 -6
  77. data/lib/brakeman/rescanner.rb +29 -31
  78. data/lib/brakeman/scanner.rb +17 -8
  79. data/lib/brakeman/tracker.rb +24 -34
  80. data/lib/brakeman/tracker/collection.rb +77 -0
  81. data/lib/brakeman/tracker/config.rb +93 -0
  82. data/lib/brakeman/tracker/controller.rb +161 -0
  83. data/lib/brakeman/tracker/library.rb +17 -0
  84. data/lib/brakeman/tracker/model.rb +90 -0
  85. data/lib/brakeman/tracker/template.rb +33 -0
  86. data/lib/brakeman/util.rb +17 -9
  87. data/lib/brakeman/version.rb +1 -1
  88. data/lib/brakeman/warning.rb +8 -9
  89. data/lib/ruby_parser/bm_sexp.rb +16 -16
  90. data/lib/ruby_parser/bm_sexp_processor.rb +1 -120
  91. metadata +42 -31
  92. checksums.yaml.gz.sig +0 -1
  93. data.tar.gz.sig +0 -0
  94. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 15522576649f902090b9d006ffe66b063172eccb
4
- data.tar.gz: 5028884d1539437c9571894dcf1ee8d580f60996
3
+ metadata.gz: 5db4cee0910ab76ab868345145436bbf8817ab04
4
+ data.tar.gz: 7633c66f5638aadb0ee5a1619755ee17e5a92ad0
5
5
  SHA512:
6
- metadata.gz: 15ca6f4ad8ea0b91ca498a862638864e76de75633c96175229f2d3314304797d24addb57eaac7a137bc729fc8477694565caea013ad0dfceb61048e077d9150f
7
- data.tar.gz: 963b6eed256fec2b7407b60918673117a40f2d504379107c4f597e8e482b84ca8bf7967fbcbdff0de417de0594398e16f6eaed16e7c0fd6ba83d8394d89025e3
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
  [![Brakeman Logo](http://brakemanscanner.org/images/logo_medium.png)](http://brakemanscanner.org/)
2
2
 
3
- [![Travis CI
4
- Status](https://secure.travis-ci.org/presidentbeef/brakeman.png)](https://travis-ci.org/presidentbeef/brakeman)
5
- [![Code
6
- Climate](https://codeclimate.com/github/presidentbeef/brakeman.png)](https://codeclimate.com/github/presidentbeef/brakeman)
3
+ [![Build Status](https://travis-ci.org/presidentbeef/brakeman.svg?branch=master)](https://travis-ci.org/presidentbeef/brakeman)
4
+ [![Code Climate](https://codeclimate.com/github/presidentbeef/brakeman/badges/gpa.svg)](https://codeclimate.com/github/presidentbeef/brakeman)
5
+ [![Test Coverage](https://codeclimate.com/github/presidentbeef/brakeman/badges/coverage.svg)](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.
@@ -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[:name]) || @current_class || @current_module || @current_set || result[:location][:class] || result[:location][: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 process_string_interp exp
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[:rails][:active_record] and
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[:gems][:protected_attributes] || (tracker.config[:rails][:active_record] &&
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[:gems][:strong_parameters]
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[:name]) || @current_class || @current_module || @current_set || result[:location][:class] || result[:location][: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 :string_interp, :dstr
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 :string_eval, :evstr
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 :string_interp, :dstr
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 :string_eval, :evstr
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 ||= tracker.config[:rails_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[:gems][:'railslts-version'] and
487
- version_between? version, "2.3.18.99", tracker.config[:gems][:'railslts-version'][:version]
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[:gems][gem_name]
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? model, :"ActiveRecord::Base"
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[:options][:http_basic_authenticate_with]
21
+ c.options[:http_basic_authenticate_with]
22
22
  end
23
23
 
24
24
  Hash[controllers].each do |name, controller|
25
- controller[:options][:http_basic_authenticate_with].each do |call|
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[:files].first
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[:outputs].each do |out|
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 and raw_call? exp
61
- out = exp.value.first_arg
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 raw_call? exp and not duplicate? exp
145
- process exp.value.first_arg
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 => :xss_to_json,
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 process_string_interp exp
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[:rails][:active_support] and
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
- target.nil? and
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 #{tracker.config[:rails_version]} with globbing routes is vulnerable to directory traversal and remote code execution. Patch or upgrade to #{upgrade}",
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[:rails][:consider_all_requests_local]
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[:public].each do |name, definition|
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 node_type? exp, :string_interp, :dstr
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, :string_eval and
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, :string_eval, :string_interp
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 #{tracker.config[:rails_version]} has a file existence disclosure. Upgrade to #{fix_version} or disable serving static assets",
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[:rails][:serve_static_assets]
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
- return unless ancestor? app_controller, :"ActionController::Base"
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[:files].first
22
+ :file => app_controller.file
26
23
 
27
- elsif app_controller and not app_controller[:options][:protect_from_forgery]
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[:files].first
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 #{tracker.config[:rails_version]} (CVE-2011-0447). Upgrade to 2.3.11 or apply patches as needed",
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 #{tracker.config[:rails_version]} (CVE-2011-0447). Upgrade to 3.0.4 or apply patches as needed",
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[:options][:protect_from_forgery]
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[:files].first
63
+ :file => app_controller.file
67
64
  }
68
65
 
69
66
  args.merge!(:code => forgery_opts.first) if forgery_opts.is_a?(Array)