brakeman-lib 4.4.0 → 4.7.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 (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +63 -0
  3. data/README.md +6 -7
  4. data/lib/brakeman.rb +7 -0
  5. data/lib/brakeman/app_tree.rb +34 -22
  6. data/lib/brakeman/call_index.rb +54 -15
  7. data/lib/brakeman/checks.rb +7 -7
  8. data/lib/brakeman/checks/base_check.rb +75 -56
  9. data/lib/brakeman/checks/check_content_tag.rb +12 -0
  10. data/lib/brakeman/checks/check_cookie_serialization.rb +22 -0
  11. data/lib/brakeman/checks/check_cross_site_scripting.rb +15 -10
  12. data/lib/brakeman/checks/check_default_routes.rb +5 -0
  13. data/lib/brakeman/checks/check_deserialize.rb +49 -0
  14. data/lib/brakeman/checks/check_dynamic_finders.rb +1 -1
  15. data/lib/brakeman/checks/check_evaluation.rb +0 -1
  16. data/lib/brakeman/checks/check_execute.rb +44 -1
  17. data/lib/brakeman/checks/check_file_access.rb +7 -1
  18. data/lib/brakeman/checks/check_force_ssl.rb +27 -0
  19. data/lib/brakeman/checks/check_header_dos.rb +2 -2
  20. data/lib/brakeman/checks/check_i18n_xss.rb +2 -2
  21. data/lib/brakeman/checks/check_jruby_xml.rb +2 -2
  22. data/lib/brakeman/checks/check_json_parsing.rb +7 -2
  23. data/lib/brakeman/checks/check_link_to_href.rb +6 -1
  24. data/lib/brakeman/checks/check_mail_to.rb +1 -1
  25. data/lib/brakeman/checks/check_mime_type_dos.rb +2 -2
  26. data/lib/brakeman/checks/check_model_attr_accessible.rb +1 -1
  27. data/lib/brakeman/checks/check_model_attributes.rb +12 -50
  28. data/lib/brakeman/checks/check_model_serialize.rb +1 -1
  29. data/lib/brakeman/checks/check_nested_attributes_bypass.rb +4 -4
  30. data/lib/brakeman/checks/check_reverse_tabnabbing.rb +54 -0
  31. data/lib/brakeman/checks/check_sanitize_methods.rb +2 -2
  32. data/lib/brakeman/checks/check_secrets.rb +1 -1
  33. data/lib/brakeman/checks/check_send.rb +0 -1
  34. data/lib/brakeman/checks/check_session_manipulation.rb +0 -1
  35. data/lib/brakeman/checks/check_session_settings.rb +15 -12
  36. data/lib/brakeman/checks/check_simple_format.rb +5 -0
  37. data/lib/brakeman/checks/check_skip_before_filter.rb +1 -1
  38. data/lib/brakeman/checks/check_sql.rb +27 -20
  39. data/lib/brakeman/checks/check_validation_regex.rb +1 -1
  40. data/lib/brakeman/checks/check_xml_dos.rb +2 -2
  41. data/lib/brakeman/checks/check_yaml_parsing.rb +10 -18
  42. data/lib/brakeman/differ.rb +16 -28
  43. data/lib/brakeman/file_parser.rb +6 -8
  44. data/lib/brakeman/file_path.rb +85 -0
  45. data/lib/brakeman/options.rb +7 -0
  46. data/lib/brakeman/parsers/haml_embedded.rb +44 -0
  47. data/lib/brakeman/parsers/slim_embedded.rb +44 -0
  48. data/lib/brakeman/parsers/template_parser.rb +8 -8
  49. data/lib/brakeman/processor.rb +4 -5
  50. data/lib/brakeman/processors/alias_processor.rb +49 -7
  51. data/lib/brakeman/processors/base_processor.rb +10 -7
  52. data/lib/brakeman/processors/controller_alias_processor.rb +10 -7
  53. data/lib/brakeman/processors/controller_processor.rb +9 -13
  54. data/lib/brakeman/processors/gem_processor.rb +10 -2
  55. data/lib/brakeman/processors/haml_template_processor.rb +92 -123
  56. data/lib/brakeman/processors/lib/call_conversion_helper.rb +4 -0
  57. data/lib/brakeman/processors/lib/find_all_calls.rb +27 -4
  58. data/lib/brakeman/processors/lib/find_call.rb +3 -64
  59. data/lib/brakeman/processors/lib/module_helper.rb +8 -8
  60. data/lib/brakeman/processors/lib/processor_helper.rb +3 -3
  61. data/lib/brakeman/processors/lib/rails2_config_processor.rb +4 -4
  62. data/lib/brakeman/processors/lib/rails2_route_processor.rb +2 -2
  63. data/lib/brakeman/processors/lib/rails3_config_processor.rb +3 -3
  64. data/lib/brakeman/processors/lib/rails3_route_processor.rb +2 -2
  65. data/lib/brakeman/processors/lib/render_helper.rb +2 -2
  66. data/lib/brakeman/processors/lib/render_path.rb +18 -1
  67. data/lib/brakeman/processors/library_processor.rb +5 -5
  68. data/lib/brakeman/processors/model_processor.rb +4 -5
  69. data/lib/brakeman/processors/output_processor.rb +5 -0
  70. data/lib/brakeman/processors/slim_template_processor.rb +16 -0
  71. data/lib/brakeman/processors/template_alias_processor.rb +32 -5
  72. data/lib/brakeman/processors/template_processor.rb +14 -10
  73. data/lib/brakeman/report.rb +3 -3
  74. data/lib/brakeman/report/ignore/config.rb +2 -3
  75. data/lib/brakeman/report/ignore/interactive.rb +2 -2
  76. data/lib/brakeman/report/pager.rb +1 -0
  77. data/lib/brakeman/report/report_base.rb +51 -6
  78. data/lib/brakeman/report/report_codeclimate.rb +3 -3
  79. data/lib/brakeman/report/report_hash.rb +1 -1
  80. data/lib/brakeman/report/report_html.rb +2 -2
  81. data/lib/brakeman/report/report_json.rb +1 -24
  82. data/lib/brakeman/report/report_table.rb +20 -4
  83. data/lib/brakeman/report/report_tabs.rb +1 -1
  84. data/lib/brakeman/report/report_text.rb +2 -2
  85. data/lib/brakeman/rescanner.rb +13 -12
  86. data/lib/brakeman/scanner.rb +24 -18
  87. data/lib/brakeman/tracker.rb +35 -7
  88. data/lib/brakeman/tracker/collection.rb +4 -3
  89. data/lib/brakeman/tracker/config.rb +44 -48
  90. data/lib/brakeman/tracker/constants.rb +2 -1
  91. data/lib/brakeman/util.rb +18 -147
  92. data/lib/brakeman/version.rb +1 -1
  93. data/lib/brakeman/warning.rb +27 -13
  94. data/lib/brakeman/warning_codes.rb +4 -0
  95. data/lib/ruby_parser/bm_sexp.rb +1 -1
  96. data/lib/ruby_parser/bm_sexp_processor.rb +1 -0
  97. metadata +58 -43
@@ -45,6 +45,16 @@ class Brakeman::CheckContentTag < Brakeman::CheckCrossSiteScripting
45
45
  def process_result result
46
46
  return if duplicate? result
47
47
 
48
+ case result[:location][:type]
49
+ when :template
50
+ @current_template = result[:location][:template]
51
+ when :class
52
+ @current_class = result[:location][:class]
53
+ @current_method = result[:location][:method]
54
+ end
55
+
56
+ @current_file = result[:location][:file]
57
+
48
58
  call = result[:call] = result[:call].dup
49
59
 
50
60
  args = call.arglist
@@ -85,6 +95,8 @@ class Brakeman::CheckContentTag < Brakeman::CheckCrossSiteScripting
85
95
  end
86
96
  end
87
97
  end
98
+ ensure
99
+ @current_template = @current_class = @current_method = @current_file = nil
88
100
  end
89
101
 
90
102
  def check_argument result, exp
@@ -0,0 +1,22 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckCookieSerialization < Brakeman::BaseCheck
4
+ Brakeman::Checks.add self
5
+
6
+ @description = "Check for use of Marshal for cookie serialization"
7
+
8
+ def run_check
9
+ tracker.find_call(target: :'Rails.application.config.action_dispatch', method: :cookies_serializer=).each do |result|
10
+ setting = result[:call].first_arg
11
+
12
+ if symbol? setting and [:marshal, :hybrid].include? setting.value
13
+ warn :result => result,
14
+ :warning_type => "Remote Code Execution",
15
+ :warning_code => :unsafe_cookie_serialization,
16
+ :message => msg("Use of unsafe cookie serialization strategy ", msg_code(setting.value.inspect), " might lead to remote code execution"),
17
+ :confidence => :medium,
18
+ :link_path => "unsafe_deserialization"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -33,6 +33,11 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
33
33
 
34
34
  FORM_BUILDER = Sexp.new(:call, Sexp.new(:const, :FormBuilder), :new)
35
35
 
36
+ def initialize *args
37
+ super
38
+ @matched = @mark = false
39
+ end
40
+
36
41
  #Run check
37
42
  def run_check
38
43
  setup
@@ -57,12 +62,12 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
57
62
 
58
63
  if exp.node_type == :output
59
64
  out = exp.value
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
65
+ end
66
+
67
+ if raw_call? exp
68
+ out = exp.value.first_arg
69
+ elsif html_safe_call? exp
70
+ out = exp.value.target
66
71
  end
67
72
 
68
73
  return if call? out and ignore_call? out.target, out.method
@@ -282,7 +287,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
282
287
 
283
288
  def setup
284
289
  @ignore_methods = Set[:==, :!=, :button_to, :check_box, :content_tag, :escapeHTML, :escape_once,
285
- :field_field, :fields_for, :h, :hidden_field,
290
+ :field_field, :fields_for, :form_for, :h, :hidden_field,
286
291
  :hidden_field, :hidden_field_tag, :image_tag, :label,
287
292
  :link_to, :mail_to, :radio_button, :select,
288
293
  :submit_tag, :text_area, :text_field,
@@ -311,11 +316,11 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
311
316
  end
312
317
 
313
318
  json_escape_on = false
314
- initializers = tracker.check_initializers :ActiveSupport, :escape_html_entities_in_json=
315
- initializers.each {|result| json_escape_on = true?(result.call.first_arg) }
319
+ initializers = tracker.find_call(target: :ActiveSupport, method: :escape_html_entities_in_json=)
320
+ initializers.each {|result| json_escape_on = true?(result[:call].first_arg) }
316
321
 
317
322
  if tracker.config.escape_html_entities_in_json?
318
- json_escape_on = true
323
+ json_escape_on = true
319
324
  elsif version_between? "4.0.0", "9.9.9"
320
325
  json_escape_on = true
321
326
  end
@@ -6,6 +6,11 @@ class Brakeman::CheckDefaultRoutes < Brakeman::BaseCheck
6
6
 
7
7
  @description = "Checks for default routes"
8
8
 
9
+ def initialize *args
10
+ super
11
+ @actions_allowed_on_controller = nil
12
+ end
13
+
9
14
  #Checks for :allow_all_actions globally and for individual routes
10
15
  #if it is not enabled globally.
11
16
  def run_check
@@ -9,6 +9,7 @@ class Brakeman::CheckDeserialize < Brakeman::BaseCheck
9
9
  check_yaml
10
10
  check_csv
11
11
  check_marshal
12
+ check_oj
12
13
  end
13
14
 
14
15
  def check_yaml
@@ -23,6 +24,26 @@ class Brakeman::CheckDeserialize < Brakeman::BaseCheck
23
24
  check_methods :Marshal, :load, :restore
24
25
  end
25
26
 
27
+ def check_oj
28
+ check_methods :Oj, :object_load # Always unsafe, regardless of mode
29
+
30
+ unsafe_mode = :object
31
+ safe_default = oj_safe_default?
32
+
33
+ tracker.find_call(:target => :Oj, :method => :load).each do |result|
34
+ call = result[:call]
35
+ options = call.second_arg
36
+
37
+ if options and hash? options and mode = hash_access(options, :mode)
38
+ if symbol? mode and mode.value == unsafe_mode
39
+ check_deserialize result, :Oj
40
+ end
41
+ elsif not safe_default
42
+ check_deserialize result, :Oj
43
+ end
44
+ end
45
+ end
46
+
26
47
  def check_methods target, *methods
27
48
  tracker.find_call(:target => target, :methods => methods ).each do |result|
28
49
  check_deserialize result, target
@@ -53,4 +74,32 @@ class Brakeman::CheckDeserialize < Brakeman::BaseCheck
53
74
  :link_path => "unsafe_deserialization"
54
75
  end
55
76
  end
77
+
78
+ private
79
+
80
+ def oj_safe_default?
81
+ safe_default = false
82
+
83
+ if tracker.find_call(target: :Oj, method: :mimic_JSON).any?
84
+ safe_default = true
85
+ elsif result = tracker.find_call(target: :Oj, method: :default_options=).first
86
+ options = result[:call].first_arg
87
+
88
+ if oj_safe_mode? options
89
+ safe_default = true
90
+ end
91
+ end
92
+
93
+ safe_default
94
+ end
95
+
96
+ def oj_safe_mode? options
97
+ if hash? options and mode = hash_access(options, :mode)
98
+ if symbol? mode and mode != :object
99
+ return true
100
+ end
101
+ end
102
+
103
+ false
104
+ end
56
105
  end
@@ -43,6 +43,6 @@ class Brakeman::CheckDynamicFinders < Brakeman::BaseCheck
43
43
  end
44
44
 
45
45
  def potentially_dangerous? method_name
46
- method_name.match /^find_by_.*(token|guid|password|api_key|activation|code|private|reset)/
46
+ method_name.match(/^find_by_.*(token|guid|password|api_key|activation|code|private|reset)/)
47
47
  end
48
48
  end
@@ -27,7 +27,6 @@ class Brakeman::CheckEvaluation < Brakeman::BaseCheck
27
27
  :warning_type => "Dangerous Eval",
28
28
  :warning_code => :code_eval,
29
29
  :message => "User input in eval",
30
- :code => result[:call],
31
30
  :user_input => input,
32
31
  :confidence => :high
33
32
  end
@@ -21,6 +21,10 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
21
21
  SHELL_ESCAPE_MODULE_METHODS = Set[:escape, :join, :shellescape, :shelljoin]
22
22
  SHELL_ESCAPE_MIXIN_METHODS = Set[:shellescape, :shelljoin]
23
23
 
24
+ # These are common shells that are known to allow the execution of commands
25
+ # via a -c flag. See dash_c_shell_command? for more info.
26
+ KNOWN_SHELL_COMMANDS = Set["sh", "bash", "ksh", "csh", "tcsh", "zsh"]
27
+
24
28
  SHELLWORDS = s(:const, :Shellwords)
25
29
 
26
30
  #Check models, controllers, and views for command injection.
@@ -42,6 +46,8 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
42
46
  end
43
47
  end
44
48
 
49
+ private
50
+
45
51
  #Processes results from Tracker#find_call.
46
52
  def process_result result
47
53
  call = result[:call]
@@ -54,7 +60,17 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
54
60
  failure = include_user_input?(args) || dangerous_interp?(args)
55
61
  end
56
62
  when :system, :exec
57
- failure = include_user_input?(first_arg) || dangerous_interp?(first_arg)
63
+ # Normally, if we're in a `system` or `exec` call, we only are worried
64
+ # about shell injection when there's a single argument, because comma-
65
+ # separated arguments are always escaped by Ruby. However, an exception is
66
+ # when the first two arguments are something like "bash -c" because then
67
+ # the third argument is effectively the command being run and might be
68
+ # a malicious executable if it comes (partially or fully) from user input.
69
+ if dash_c_shell_command?(first_arg, call.second_arg)
70
+ failure = include_user_input?(args[3]) || dangerous_interp?(args[3])
71
+ else
72
+ failure = include_user_input?(first_arg) || dangerous_interp?(first_arg)
73
+ end
58
74
  else
59
75
  failure = include_user_input?(args) || dangerous_interp?(args)
60
76
  end
@@ -77,6 +93,15 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
77
93
  end
78
94
  end
79
95
 
96
+ # @return [Boolean] true iff the command given by `first_arg`, `second_arg`
97
+ # invokes a new shell process via `<shell_command> -c` (like `bash -c`)
98
+ def dash_c_shell_command?(first_arg, second_arg)
99
+ string?(first_arg) &&
100
+ KNOWN_SHELL_COMMANDS.include?(first_arg.value) &&
101
+ string?(second_arg) &&
102
+ second_arg.value == "-c"
103
+ end
104
+
80
105
  def check_open_calls
81
106
  tracker.find_call(:targets => [nil, :Kernel], :method => :open).each do |result|
82
107
  if match = dangerous_open_arg?(result[:call].first_arg)
@@ -90,6 +115,24 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
90
115
  end
91
116
  end
92
117
 
118
+ def include_user_input? exp
119
+ if node_type? exp, :arglist, :dstr, :evstr, :dxstr
120
+ exp.each_sexp do |e|
121
+ if res = include_user_input?(e)
122
+ return res
123
+ end
124
+ end
125
+
126
+ false
127
+ else
128
+ if shell_escape? exp
129
+ false
130
+ else
131
+ super exp
132
+ end
133
+ end
134
+ end
135
+
93
136
  def dangerous_open_arg? exp
94
137
  if string_interp? exp
95
138
  # Check for input at start of string
@@ -32,7 +32,7 @@ class Brakeman::CheckFileAccess < Brakeman::BaseCheck
32
32
 
33
33
  file_name = call.first_arg
34
34
 
35
- return if called_on_tempfile?(file_name)
35
+ return if called_on_tempfile?(file_name) || sanitized?(file_name)
36
36
 
37
37
  if match = has_immediate_user_input?(file_name)
38
38
  confidence = :high
@@ -71,6 +71,12 @@ class Brakeman::CheckFileAccess < Brakeman::BaseCheck
71
71
  call?(file_name) && file_name.target == s(:const, :Tempfile)
72
72
  end
73
73
 
74
+ def sanitized? file
75
+ call?(file) &&
76
+ call?(file.target) &&
77
+ class_name(file.target.target) == :"ActiveStorage::Filename"
78
+ end
79
+
74
80
  def temp_file_method? exp
75
81
  if call? exp
76
82
  return true if exp.call_chain.include? :tempfile
@@ -0,0 +1,27 @@
1
+ class Brakeman::CheckForceSSL < Brakeman::BaseCheck
2
+ Brakeman::Checks.add_optional self
3
+
4
+ @description = "Check that force_ssl setting is enabled in production"
5
+
6
+ def run_check
7
+ return if tracker.config.rails.empty? or tracker.config.rails_version.nil?
8
+ return if tracker.config.rails_version < "3.1.0"
9
+
10
+ force_ssl = tracker.config.rails[:force_ssl]
11
+
12
+ if false? force_ssl or force_ssl.nil?
13
+ line = if sexp? force_ssl
14
+ force_ssl.line
15
+ else
16
+ 1
17
+ end
18
+
19
+ warn :warning_type => "Missing Encryption",
20
+ :warning_code => :force_ssl_disabled,
21
+ :message => msg("The application does not force use of HTTPS: ", msg_code("config.force_ssl"), " is not enabled"),
22
+ :confidence => :high,
23
+ :file => "config/environments/production.rb",
24
+ :line => line
25
+ end
26
+ end
27
+ end
@@ -25,7 +25,7 @@ class Brakeman::CheckHeaderDoS < Brakeman::BaseCheck
25
25
  end
26
26
 
27
27
  def has_workaround?
28
- tracker.check_initializers(:ActiveSupport, :on_load).any? and
29
- tracker.check_initializers(:"ActionView::LookupContext::DetailsKey", :class_eval).any?
28
+ tracker.find_call(target: :ActiveSupport, method: :on_load).any? and
29
+ tracker.find_call(target: :"ActionView::LookupContext::DetailsKey", method: :class_eval).any?
30
30
  end
31
31
  end
@@ -41,8 +41,8 @@ class Brakeman::CheckI18nXSS < Brakeman::BaseCheck
41
41
  end
42
42
 
43
43
  def has_workaround?
44
- tracker.check_initializers(:I18n, :const_defined?).any? do |match|
45
- match.last.first_arg == s(:lit, :MissingTranslation)
44
+ tracker.find_call(target: :I18n, method: :const_defined?, chained: true).any? do |match|
45
+ match[:call].first_arg == s(:lit, :MissingTranslation)
46
46
  end
47
47
  end
48
48
  end
@@ -20,8 +20,8 @@ class Brakeman::CheckJRubyXML < Brakeman::BaseCheck
20
20
  end
21
21
 
22
22
  #Check for workaround
23
- tracker.check_initializers(:"ActiveSupport::XmlMini", :backend=).each do |result|
24
- arg = result.call.first_arg
23
+ tracker.find_call(target: :"ActiveSupport::XmlMini", method: :backend=, chained: true).each do |result|
24
+ arg = result[:call].first_arg
25
25
 
26
26
  return if string? arg and arg.value == "REXML"
27
27
  end
@@ -5,6 +5,11 @@ class Brakeman::CheckJSONParsing < Brakeman::BaseCheck
5
5
 
6
6
  @description = "Checks for JSON parsing vulnerabilities CVE-2013-0333 and CVE-2013-0269"
7
7
 
8
+ def initialize *args
9
+ super
10
+ @uses_json_parse = nil
11
+ end
12
+
8
13
  def run_check
9
14
  check_cve_2013_0333
10
15
  check_cve_2013_0269
@@ -39,13 +44,13 @@ class Brakeman::CheckJSONParsing < Brakeman::BaseCheck
39
44
 
40
45
  #Check for `ActiveSupport::JSON.backend = "JSONGem"`
41
46
  def uses_gem_backend?
42
- matches = tracker.check_initializers(:'ActiveSupport::JSON', :backend=)
47
+ matches = tracker.find_call(target: :'ActiveSupport::JSON', method: :backend=, chained: true)
43
48
 
44
49
  unless matches.empty?
45
50
  json_gem = s(:str, "JSONGem")
46
51
 
47
52
  matches.each do |result|
48
- if result.call.first_arg == json_gem
53
+ if result[:call].first_arg == json_gem
49
54
  return true
50
55
  end
51
56
  end
@@ -34,7 +34,12 @@ class Brakeman::CheckLinkToHref < Brakeman::CheckLinkTo
34
34
  #an ignored method call by the code above.
35
35
  call = result[:call] = result[:call].dup
36
36
  @matched = false
37
- url_arg = process call.second_arg
37
+
38
+ url_arg = if result[:block]
39
+ process call.first_arg
40
+ else
41
+ process call.second_arg
42
+ end
38
43
 
39
44
  if check_argument? url_arg
40
45
  url_arg = url_arg.first_arg
@@ -24,7 +24,7 @@ class Brakeman::CheckMailTo < Brakeman::BaseCheck
24
24
  :warning_code => :CVE_2011_0446,
25
25
  :message => message,
26
26
  :confidence => :high,
27
- :gem_info => gemfile_or_environment,
27
+ :gem_info => gemfile_or_environment, # Probably ignored now
28
28
  :link_path => "https://groups.google.com/d/topic/rubyonrails-security/8CpI7egxX4E/discussion"
29
29
  end
30
30
  end
@@ -30,8 +30,8 @@ class Brakeman::CheckMimeTypeDoS < Brakeman::BaseCheck
30
30
  end
31
31
 
32
32
  def has_workaround?
33
- tracker.check_initializers(:Mime, :const_set).any? do |match|
34
- arg = match.call.first_arg
33
+ tracker.find_call(target: :Mime, method: :const_set).any? do |match|
34
+ arg = match[:call].first_arg
35
35
 
36
36
  symbol? arg and arg.value == :LOOKUP
37
37
  end
@@ -25,7 +25,7 @@ class Brakeman::CheckModelAttrAccessible < Brakeman::BaseCheck
25
25
 
26
26
  SUSP_ATTRS.each do |susp_attr, confidence|
27
27
  if susp_attr.is_a?(Regexp) and susp_attr =~ attribute.to_s or susp_attr == attribute
28
- warn :model => name,
28
+ warn :model => model,
29
29
  :file => model.file,
30
30
  :warning_type => "Mass Assignment",
31
31
  :warning_code => :dangerous_attr_accessible,
@@ -2,9 +2,6 @@ require 'brakeman/checks/base_check'
2
2
 
3
3
  #Check if mass assignment is used with models
4
4
  #which inherit from ActiveRecord::Base.
5
- #
6
- #If tracker.options[:collapse_mass_assignment] is +true+ (default), all models
7
- #which do not use attr_accessible will be reported in a single warning
8
5
  class Brakeman::CheckModelAttributes < Brakeman::BaseCheck
9
6
  Brakeman::Checks.add self
10
7
 
@@ -15,26 +12,19 @@ class Brakeman::CheckModelAttributes < Brakeman::BaseCheck
15
12
 
16
13
  #Roll warnings into one warning for all models
17
14
  if tracker.options[:collapse_mass_assignment]
18
- no_accessible_names = []
19
- protected_names = []
20
-
21
- check_models do |name, model|
22
- if model.attr_protected.nil?
23
- no_accessible_names << name.to_s
24
- elsif not tracker.options[:ignore_attr_protected]
25
- protected_names << name.to_s
26
- end
27
- end
15
+ Brakeman.notify "[Notice] The `collapse_mass_assignment` option has been removed."
16
+ end
28
17
 
29
- unless no_accessible_names.empty?
30
- warn :model => no_accessible_names.sort.join(", "),
18
+ check_models do |name, model|
19
+ if model.attr_protected.nil?
20
+ warn :model => model,
21
+ :file => model.file,
22
+ :line => model.top_line,
31
23
  :warning_type => "Attribute Restriction",
32
24
  :warning_code => :no_attr_accessible,
33
25
  :message => msg("Mass assignment is not restricted using ", msg_code("attr_accessible")),
34
26
  :confidence => :high
35
- end
36
-
37
- unless protected_names.empty?
27
+ elsif not tracker.options[:ignore_attr_protected]
38
28
  message, confidence, link = check_for_attr_protected_bypass
39
29
 
40
30
  if link
@@ -43,41 +33,13 @@ class Brakeman::CheckModelAttributes < Brakeman::BaseCheck
43
33
  warning_code = :attr_protected_used
44
34
  end
45
35
 
46
- warn :model => protected_names.sort.join(", "),
36
+ warn :model => model,
37
+ :file => model.file,
38
+ :line => model.attr_protected.first.line,
47
39
  :warning_type => "Attribute Restriction",
48
40
  :warning_code => warning_code,
49
41
  :message => message,
50
- :confidence => confidence,
51
- :link => link
52
- end
53
- else #Output one warning per model
54
-
55
- check_models do |name, model|
56
- if model.attr_protected.nil?
57
- warn :model => name,
58
- :file => model.file,
59
- :line => model.top_line,
60
- :warning_type => "Attribute Restriction",
61
- :warning_code => :no_attr_accessible,
62
- :message => msg("Mass assignment is not restricted using ", msg_code("attr_accessible")),
63
- :confidence => :high
64
- elsif not tracker.options[:ignore_attr_protected]
65
- message, confidence, link = check_for_attr_protected_bypass
66
-
67
- if link
68
- warning_code = :CVE_2013_0276
69
- else
70
- warning_code = :attr_protected_used
71
- end
72
-
73
- warn :model => name,
74
- :file => model.file,
75
- :line => model.attr_protected.first.line,
76
- :warning_type => "Attribute Restriction",
77
- :warning_code => warning_code,
78
- :message => message,
79
- :confidence => confidence
80
- end
42
+ :confidence => confidence
81
43
  end
82
44
  end
83
45
  end