brakeman 3.0.5 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
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)