brakeman-lib 3.3.1

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 (159) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +872 -0
  3. data/FEATURES +16 -0
  4. data/README.md +169 -0
  5. data/WARNING_TYPES +95 -0
  6. data/bin/brakeman +89 -0
  7. data/lib/brakeman.rb +495 -0
  8. data/lib/brakeman/app_tree.rb +161 -0
  9. data/lib/brakeman/brakeman.rake +17 -0
  10. data/lib/brakeman/call_index.rb +219 -0
  11. data/lib/brakeman/checks.rb +191 -0
  12. data/lib/brakeman/checks/base_check.rb +518 -0
  13. data/lib/brakeman/checks/check_basic_auth.rb +88 -0
  14. data/lib/brakeman/checks/check_basic_auth_timing_attack.rb +33 -0
  15. data/lib/brakeman/checks/check_content_tag.rb +160 -0
  16. data/lib/brakeman/checks/check_create_with.rb +75 -0
  17. data/lib/brakeman/checks/check_cross_site_scripting.rb +385 -0
  18. data/lib/brakeman/checks/check_default_routes.rb +86 -0
  19. data/lib/brakeman/checks/check_deserialize.rb +57 -0
  20. data/lib/brakeman/checks/check_detailed_exceptions.rb +55 -0
  21. data/lib/brakeman/checks/check_digest_dos.rb +38 -0
  22. data/lib/brakeman/checks/check_dynamic_finders.rb +49 -0
  23. data/lib/brakeman/checks/check_escape_function.rb +21 -0
  24. data/lib/brakeman/checks/check_evaluation.rb +36 -0
  25. data/lib/brakeman/checks/check_execute.rb +167 -0
  26. data/lib/brakeman/checks/check_file_access.rb +63 -0
  27. data/lib/brakeman/checks/check_file_disclosure.rb +35 -0
  28. data/lib/brakeman/checks/check_filter_skipping.rb +31 -0
  29. data/lib/brakeman/checks/check_forgery_setting.rb +74 -0
  30. data/lib/brakeman/checks/check_header_dos.rb +31 -0
  31. data/lib/brakeman/checks/check_i18n_xss.rb +48 -0
  32. data/lib/brakeman/checks/check_jruby_xml.rb +38 -0
  33. data/lib/brakeman/checks/check_json_encoding.rb +47 -0
  34. data/lib/brakeman/checks/check_json_parsing.rb +107 -0
  35. data/lib/brakeman/checks/check_link_to.rb +132 -0
  36. data/lib/brakeman/checks/check_link_to_href.rb +115 -0
  37. data/lib/brakeman/checks/check_mail_to.rb +49 -0
  38. data/lib/brakeman/checks/check_mass_assignment.rb +198 -0
  39. data/lib/brakeman/checks/check_mime_type_dos.rb +39 -0
  40. data/lib/brakeman/checks/check_model_attr_accessible.rb +55 -0
  41. data/lib/brakeman/checks/check_model_attributes.rb +119 -0
  42. data/lib/brakeman/checks/check_model_serialize.rb +67 -0
  43. data/lib/brakeman/checks/check_nested_attributes.rb +38 -0
  44. data/lib/brakeman/checks/check_nested_attributes_bypass.rb +58 -0
  45. data/lib/brakeman/checks/check_number_to_currency.rb +74 -0
  46. data/lib/brakeman/checks/check_quote_table_name.rb +40 -0
  47. data/lib/brakeman/checks/check_redirect.rb +215 -0
  48. data/lib/brakeman/checks/check_regex_dos.rb +69 -0
  49. data/lib/brakeman/checks/check_render.rb +92 -0
  50. data/lib/brakeman/checks/check_render_dos.rb +37 -0
  51. data/lib/brakeman/checks/check_render_inline.rb +54 -0
  52. data/lib/brakeman/checks/check_response_splitting.rb +21 -0
  53. data/lib/brakeman/checks/check_route_dos.rb +42 -0
  54. data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +31 -0
  55. data/lib/brakeman/checks/check_sanitize_methods.rb +79 -0
  56. data/lib/brakeman/checks/check_secrets.rb +40 -0
  57. data/lib/brakeman/checks/check_select_tag.rb +60 -0
  58. data/lib/brakeman/checks/check_select_vulnerability.rb +60 -0
  59. data/lib/brakeman/checks/check_send.rb +48 -0
  60. data/lib/brakeman/checks/check_send_file.rb +19 -0
  61. data/lib/brakeman/checks/check_session_manipulation.rb +36 -0
  62. data/lib/brakeman/checks/check_session_settings.rb +170 -0
  63. data/lib/brakeman/checks/check_simple_format.rb +59 -0
  64. data/lib/brakeman/checks/check_single_quotes.rb +101 -0
  65. data/lib/brakeman/checks/check_skip_before_filter.rb +60 -0
  66. data/lib/brakeman/checks/check_sql.rb +660 -0
  67. data/lib/brakeman/checks/check_sql_cves.rb +101 -0
  68. data/lib/brakeman/checks/check_ssl_verify.rb +49 -0
  69. data/lib/brakeman/checks/check_strip_tags.rb +89 -0
  70. data/lib/brakeman/checks/check_symbol_dos.rb +64 -0
  71. data/lib/brakeman/checks/check_symbol_dos_cve.rb +30 -0
  72. data/lib/brakeman/checks/check_translate_bug.rb +45 -0
  73. data/lib/brakeman/checks/check_unsafe_reflection.rb +51 -0
  74. data/lib/brakeman/checks/check_unscoped_find.rb +41 -0
  75. data/lib/brakeman/checks/check_validation_regex.rb +116 -0
  76. data/lib/brakeman/checks/check_weak_hash.rb +151 -0
  77. data/lib/brakeman/checks/check_without_protection.rb +80 -0
  78. data/lib/brakeman/checks/check_xml_dos.rb +51 -0
  79. data/lib/brakeman/checks/check_yaml_parsing.rb +121 -0
  80. data/lib/brakeman/differ.rb +66 -0
  81. data/lib/brakeman/file_parser.rb +50 -0
  82. data/lib/brakeman/format/style.css +133 -0
  83. data/lib/brakeman/options.rb +301 -0
  84. data/lib/brakeman/parsers/rails2_erubis.rb +6 -0
  85. data/lib/brakeman/parsers/rails2_xss_plugin_erubis.rb +48 -0
  86. data/lib/brakeman/parsers/rails3_erubis.rb +74 -0
  87. data/lib/brakeman/parsers/template_parser.rb +89 -0
  88. data/lib/brakeman/processor.rb +102 -0
  89. data/lib/brakeman/processors/alias_processor.rb +1013 -0
  90. data/lib/brakeman/processors/base_processor.rb +277 -0
  91. data/lib/brakeman/processors/config_processor.rb +14 -0
  92. data/lib/brakeman/processors/controller_alias_processor.rb +273 -0
  93. data/lib/brakeman/processors/controller_processor.rb +326 -0
  94. data/lib/brakeman/processors/erb_template_processor.rb +80 -0
  95. data/lib/brakeman/processors/erubis_template_processor.rb +104 -0
  96. data/lib/brakeman/processors/gem_processor.rb +57 -0
  97. data/lib/brakeman/processors/haml_template_processor.rb +190 -0
  98. data/lib/brakeman/processors/lib/basic_processor.rb +37 -0
  99. data/lib/brakeman/processors/lib/find_all_calls.rb +223 -0
  100. data/lib/brakeman/processors/lib/find_call.rb +183 -0
  101. data/lib/brakeman/processors/lib/find_return_value.rb +134 -0
  102. data/lib/brakeman/processors/lib/processor_helper.rb +75 -0
  103. data/lib/brakeman/processors/lib/rails2_config_processor.rb +145 -0
  104. data/lib/brakeman/processors/lib/rails2_route_processor.rb +313 -0
  105. data/lib/brakeman/processors/lib/rails3_config_processor.rb +132 -0
  106. data/lib/brakeman/processors/lib/rails3_route_processor.rb +308 -0
  107. data/lib/brakeman/processors/lib/render_helper.rb +181 -0
  108. data/lib/brakeman/processors/lib/render_path.rb +107 -0
  109. data/lib/brakeman/processors/lib/route_helper.rb +68 -0
  110. data/lib/brakeman/processors/lib/safe_call_helper.rb +16 -0
  111. data/lib/brakeman/processors/library_processor.rb +119 -0
  112. data/lib/brakeman/processors/model_processor.rb +191 -0
  113. data/lib/brakeman/processors/output_processor.rb +171 -0
  114. data/lib/brakeman/processors/route_processor.rb +17 -0
  115. data/lib/brakeman/processors/slim_template_processor.rb +107 -0
  116. data/lib/brakeman/processors/template_alias_processor.rb +116 -0
  117. data/lib/brakeman/processors/template_processor.rb +74 -0
  118. data/lib/brakeman/report.rb +78 -0
  119. data/lib/brakeman/report/config/remediation.yml +71 -0
  120. data/lib/brakeman/report/ignore/config.rb +135 -0
  121. data/lib/brakeman/report/ignore/interactive.rb +311 -0
  122. data/lib/brakeman/report/renderer.rb +24 -0
  123. data/lib/brakeman/report/report_base.rb +286 -0
  124. data/lib/brakeman/report/report_codeclimate.rb +70 -0
  125. data/lib/brakeman/report/report_csv.rb +55 -0
  126. data/lib/brakeman/report/report_hash.rb +23 -0
  127. data/lib/brakeman/report/report_html.rb +216 -0
  128. data/lib/brakeman/report/report_json.rb +42 -0
  129. data/lib/brakeman/report/report_markdown.rb +156 -0
  130. data/lib/brakeman/report/report_table.rb +107 -0
  131. data/lib/brakeman/report/report_tabs.rb +17 -0
  132. data/lib/brakeman/report/templates/controller_overview.html.erb +22 -0
  133. data/lib/brakeman/report/templates/controller_warnings.html.erb +21 -0
  134. data/lib/brakeman/report/templates/error_overview.html.erb +29 -0
  135. data/lib/brakeman/report/templates/header.html.erb +58 -0
  136. data/lib/brakeman/report/templates/ignored_warnings.html.erb +25 -0
  137. data/lib/brakeman/report/templates/model_warnings.html.erb +21 -0
  138. data/lib/brakeman/report/templates/overview.html.erb +38 -0
  139. data/lib/brakeman/report/templates/security_warnings.html.erb +23 -0
  140. data/lib/brakeman/report/templates/template_overview.html.erb +21 -0
  141. data/lib/brakeman/report/templates/view_warnings.html.erb +34 -0
  142. data/lib/brakeman/report/templates/warning_overview.html.erb +17 -0
  143. data/lib/brakeman/rescanner.rb +483 -0
  144. data/lib/brakeman/scanner.rb +317 -0
  145. data/lib/brakeman/tracker.rb +347 -0
  146. data/lib/brakeman/tracker/collection.rb +93 -0
  147. data/lib/brakeman/tracker/config.rb +101 -0
  148. data/lib/brakeman/tracker/constants.rb +101 -0
  149. data/lib/brakeman/tracker/controller.rb +161 -0
  150. data/lib/brakeman/tracker/library.rb +17 -0
  151. data/lib/brakeman/tracker/model.rb +90 -0
  152. data/lib/brakeman/tracker/template.rb +33 -0
  153. data/lib/brakeman/util.rb +481 -0
  154. data/lib/brakeman/version.rb +3 -0
  155. data/lib/brakeman/warning.rb +255 -0
  156. data/lib/brakeman/warning_codes.rb +111 -0
  157. data/lib/ruby_parser/bm_sexp.rb +610 -0
  158. data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
  159. metadata +362 -0
@@ -0,0 +1,132 @@
1
+ require 'brakeman/checks/check_cross_site_scripting'
2
+
3
+ #Checks for calls to link_to in versions of Ruby where link_to did not
4
+ #escape the first argument.
5
+ #
6
+ #See https://rails.lighthouseapp.com/projects/8994/tickets/3518-link_to-doesnt-escape-its-input
7
+ class Brakeman::CheckLinkTo < Brakeman::CheckCrossSiteScripting
8
+ Brakeman::Checks.add self
9
+
10
+ @description = "Checks for XSS in link_to in versions before 3.0"
11
+
12
+ def run_check
13
+ return unless version_between?("2.0.0", "2.9.9") and not tracker.config.escape_html?
14
+
15
+ @ignore_methods = Set[:button_to, :check_box, :escapeHTML, :escape_once,
16
+ :field_field, :fields_for, :h, :hidden_field,
17
+ :hidden_field, :hidden_field_tag, :image_tag, :label,
18
+ :mail_to, :radio_button, :select,
19
+ :submit_tag, :text_area, :text_field,
20
+ :text_field_tag, :url_encode, :u, :url_for,
21
+ :will_paginate].merge tracker.options[:safe_methods]
22
+
23
+ @known_dangerous = []
24
+ #Ideally, I think this should also check to see if people are setting
25
+ #:escape => false
26
+ @models = tracker.models.keys
27
+ @inspect_arguments = tracker.options[:check_arguments]
28
+
29
+ tracker.find_call(:target => false, :method => :link_to).each {|call| process_result call}
30
+ end
31
+
32
+ def process_result result
33
+ return if duplicate? result
34
+
35
+ #Have to make a copy of this, otherwise it will be changed to
36
+ #an ignored method call by the code above.
37
+ call = result[:call] = result[:call].dup
38
+
39
+ first_arg = call.first_arg
40
+ second_arg = call.second_arg
41
+
42
+ @matched = false
43
+
44
+ #Skip if no arguments(?) or first argument is a hash
45
+ return if first_arg.nil? or hash? first_arg
46
+
47
+ if version_between? "2.0.0", "2.2.99"
48
+ check_argument result, first_arg
49
+
50
+ if second_arg and not hash? second_arg
51
+ check_argument result, second_arg
52
+ end
53
+ elsif second_arg
54
+ #Only check first argument if there is a second argument
55
+ #in Rails 2.3.x
56
+ check_argument result, first_arg
57
+ end
58
+ end
59
+
60
+ # Check the argument for possible xss exploits
61
+ def check_argument result, exp
62
+ argument = process(exp)
63
+ !check_user_input(result, argument) && !check_method(result, argument) && !check_matched(result, @matched)
64
+ end
65
+
66
+ # Check we should warn about the user input
67
+ def check_user_input(result, argument)
68
+ input = has_immediate_user_input?(argument)
69
+ return false unless input
70
+
71
+ message = "Unescaped #{friendly_type_of input} in link_to"
72
+
73
+ warn_xss(result, message, input, CONFIDENCE[:high])
74
+ end
75
+
76
+ # Check if we should warn about the specified method
77
+ def check_method(result, argument)
78
+ return false if tracker.options[:ignore_model_output]
79
+ match = has_immediate_model?(argument)
80
+ return false unless match
81
+ method = match.method
82
+ return false if IGNORE_MODEL_METHODS.include? method
83
+
84
+ confidence = CONFIDENCE[:med]
85
+ confidence = CONFIDENCE[:high] if likely_model_attribute? match
86
+ warn_xss(result, "Unescaped model attribute in link_to", match, confidence)
87
+ end
88
+
89
+ # Check if we should warn about the matched result
90
+ def check_matched(result, matched = nil)
91
+ return false unless matched
92
+ return false if matched.type == :model and tracker.options[:ignore_model_output]
93
+
94
+ message = "Unescaped #{friendly_type_of matched} in link_to"
95
+
96
+ warn_xss(result, message, @matched, CONFIDENCE[:med])
97
+ end
98
+
99
+ # Create a warn for this xss
100
+ def warn_xss(result, message, user_input, confidence)
101
+ add_result(result)
102
+ warn :result => result,
103
+ :warning_type => "Cross Site Scripting",
104
+ :warning_code => :xss_link_to,
105
+ :message => message,
106
+ :user_input => user_input,
107
+ :confidence => confidence,
108
+ :link_path => "link_to"
109
+
110
+ true
111
+ end
112
+
113
+ def process_call exp
114
+ @mark = true
115
+ actually_process_call exp
116
+ exp
117
+ end
118
+
119
+ def actually_process_call exp
120
+ return if @matched
121
+
122
+ target = exp.target
123
+ target = process target.dup if sexp? target
124
+
125
+ #Bare records create links to the model resource,
126
+ #not a string that could have injection
127
+ #TODO: Needs test? I think this is broken?
128
+ return exp if model_name? target and context == [:call, :arglist]
129
+
130
+ super
131
+ end
132
+ end
@@ -0,0 +1,115 @@
1
+ require 'brakeman/checks/check_cross_site_scripting'
2
+
3
+ #Checks for calls to link_to which pass in potentially hazardous data
4
+ #to the second argument. While this argument must be html_safe to not break
5
+ #the html, it must also be url safe as determined by calling a
6
+ #:url_safe_method. This prevents attacks such as javascript:evil() or
7
+ #data:<encoded XSS> which is html_safe, but not safe as an href
8
+ #Props to Nick Green for the idea.
9
+ class Brakeman::CheckLinkToHref < Brakeman::CheckLinkTo
10
+ Brakeman::Checks.add self
11
+
12
+ @description = "Checks to see if values used for hrefs are sanitized using a :url_safe_method to protect against javascript:/data: XSS"
13
+
14
+ def run_check
15
+ @ignore_methods = Set[:button_to, :check_box,
16
+ :field_field, :fields_for, :hidden_field,
17
+ :hidden_field, :hidden_field_tag, :image_tag, :label,
18
+ :mail_to, :polymorphic_url, :radio_button, :select, :slice,
19
+ :submit_tag, :text_area, :text_field,
20
+ :text_field_tag, :url_encode, :u, :url_for,
21
+ :will_paginate].merge(tracker.options[:url_safe_methods] || [])
22
+
23
+ @models = tracker.models.keys
24
+ @inspect_arguments = tracker.options[:check_arguments]
25
+
26
+ methods = tracker.find_call :target => false, :method => :link_to
27
+ methods.each do |call|
28
+ process_result call
29
+ end
30
+ end
31
+
32
+ def process_result result
33
+ #Have to make a copy of this, otherwise it will be changed to
34
+ #an ignored method call by the code above.
35
+ call = result[:call] = result[:call].dup
36
+ @matched = false
37
+ url_arg = process call.second_arg
38
+
39
+ #Ignore situations where the href is an interpolated string
40
+ #with something before the user input
41
+ return if string_interp?(url_arg) && !url_arg[1].chomp.empty?
42
+
43
+ return if call? url_arg and ignore_call? url_arg.target, url_arg.method
44
+
45
+ if input = has_immediate_user_input?(url_arg)
46
+ message = "Unsafe #{friendly_type_of input} in link_to href"
47
+
48
+ unless duplicate? result
49
+ add_result result
50
+ warn :result => result,
51
+ :warning_type => "Cross Site Scripting",
52
+ :warning_code => :xss_link_to_href,
53
+ :message => message,
54
+ :user_input => input,
55
+ :confidence => CONFIDENCE[:high],
56
+ :link_path => "link_to_href"
57
+ end
58
+ elsif has_immediate_model? url_arg or model_find_call? url_arg
59
+
60
+ # Decided NOT warn on models. polymorphic_path is called it a model is
61
+ # passed to link_to (which passes it to url_for)
62
+
63
+ elsif array? url_arg
64
+ # Just like models, polymorphic path/url is called if the argument is
65
+ # an array
66
+
67
+ elsif hash? url_arg
68
+
69
+ # url_for uses the key/values pretty carefully and I don't see a risk.
70
+ # IF you have default routes AND you accept user input for :controller
71
+ # and :only_path, then MAYBE you could trigger a javascript:/data:
72
+ # attack.
73
+
74
+ elsif @matched
75
+ if @matched.type == :model and not tracker.options[:ignore_model_output]
76
+ message = "Unsafe model attribute in link_to href"
77
+ elsif @matched.type == :params
78
+ message = "Unsafe parameter value in link_to href"
79
+ end
80
+
81
+ if message and not duplicate? result
82
+ add_result result
83
+ warn :result => result,
84
+ :warning_type => "Cross Site Scripting",
85
+ :warning_code => :xss_link_to_href,
86
+ :message => message,
87
+ :user_input => @matched,
88
+ :confidence => CONFIDENCE[:med],
89
+ :link_path => "link_to_href"
90
+ end
91
+ end
92
+ end
93
+
94
+ def ignore_call? target, method
95
+ decorated_model? method or super
96
+ end
97
+
98
+ def decorated_model? method
99
+ tracker.config.has_gem? :draper and
100
+ method == :decorate
101
+ end
102
+
103
+ def ignored_method? target, method
104
+ @ignore_methods.include? method or
105
+ method.to_s =~ /_path$/ or
106
+ (target.nil? and method.to_s =~ /_url$/)
107
+ end
108
+
109
+ def model_find_call? exp
110
+ return unless call? exp
111
+
112
+ MODEL_METHODS.include? exp.method or
113
+ exp.method.to_s =~ /^find_by_/
114
+ end
115
+ end
@@ -0,0 +1,49 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ #Check for cross site scripting vulnerability in mail_to :encode => :javascript
4
+ #with certain versions of Rails (< 2.3.11 or < 3.0.4).
5
+ #
6
+ #http://groups.google.com/group/rubyonrails-security/browse_thread/thread/f02a48ede8315f81
7
+ class Brakeman::CheckMailTo < Brakeman::BaseCheck
8
+ Brakeman::Checks.add self
9
+
10
+ @description = "Checks for mail_to XSS vulnerability in certain versions"
11
+
12
+ def run_check
13
+ if (version_between? "2.3.0", "2.3.10" or version_between? "3.0.0", "3.0.3") and result = mail_to_javascript?
14
+ message = "Vulnerability in mail_to using javascript encoding (CVE-2011-0446). Upgrade to Rails version "
15
+
16
+ if version_between? "2.3.0", "2.3.10"
17
+ message << "2.3.11"
18
+ else
19
+ message << "3.0.4"
20
+ end
21
+
22
+ warn :result => result,
23
+ :warning_type => "Mail Link",
24
+ :warning_code => :CVE_2011_0446,
25
+ :message => message,
26
+ :confidence => CONFIDENCE[:high],
27
+ :gem_info => gemfile_or_environment,
28
+ :link_path => "https://groups.google.com/d/topic/rubyonrails-security/8CpI7egxX4E/discussion"
29
+ end
30
+ end
31
+
32
+ #Check for javascript encoding of mail_to address
33
+ # mail_to email, name, :encode => :javascript
34
+ def mail_to_javascript?
35
+ Brakeman.debug "Checking calls to mail_to for javascript encoding"
36
+
37
+ tracker.find_call(:target => false, :method => :mail_to).each do |result|
38
+ result[:call].each_arg do |arg|
39
+ if hash? arg
40
+ if option = hash_access(arg, :encode)
41
+ return result if symbol? option and option.value == :javascript
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ false
48
+ end
49
+ end
@@ -0,0 +1,198 @@
1
+ require 'brakeman/checks/base_check'
2
+ require 'set'
3
+
4
+ #Checks for mass assignments to models.
5
+ #
6
+ #See http://guides.rubyonrails.org/security.html#mass-assignment for details
7
+ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck
8
+ Brakeman::Checks.add self
9
+
10
+ @description = "Finds instances of mass assignment"
11
+
12
+ def initialize(*)
13
+ super
14
+ @mass_assign_calls = nil
15
+ end
16
+
17
+ def run_check
18
+ check_mass_assignment
19
+ check_permit!
20
+ end
21
+
22
+ def find_mass_assign_calls
23
+ return @mass_assign_calls if @mass_assign_calls
24
+
25
+ models = []
26
+ tracker.models.each do |name, m|
27
+ if m.is_a? Hash
28
+ p m
29
+ end
30
+ if m.unprotected_model?
31
+ models << name
32
+ end
33
+ end
34
+
35
+ return [] if models.empty?
36
+
37
+ Brakeman.debug "Finding possible mass assignment calls on #{models.length} models"
38
+ @mass_assign_calls = tracker.find_call :chained => true, :targets => models, :methods => [:new,
39
+ :attributes=,
40
+ :update_attributes,
41
+ :update_attributes!,
42
+ :create,
43
+ :create!,
44
+ :build,
45
+ :first_or_create,
46
+ :first_or_create!,
47
+ :first_or_initialize!,
48
+ :assign_attributes,
49
+ :update
50
+ ]
51
+ end
52
+
53
+ def check_mass_assignment
54
+ return if mass_assign_disabled?
55
+
56
+ Brakeman.debug "Processing possible mass assignment calls"
57
+ find_mass_assign_calls.each do |result|
58
+ process_result result
59
+ end
60
+ end
61
+
62
+ #All results should be Model.new(...) or Model.attributes=() calls
63
+ def process_result res
64
+ call = res[:call]
65
+
66
+ check = check_call call
67
+
68
+ if check and not call.original_line and not duplicate? res
69
+ add_result res
70
+
71
+ model = tracker.models[res[:chain].first]
72
+
73
+ attr_protected = (model and model.attr_protected)
74
+
75
+ if attr_protected and tracker.options[:ignore_attr_protected]
76
+ return
77
+ elsif input = include_user_input?(call.arglist)
78
+ first_arg = call.first_arg
79
+
80
+ if call? first_arg and (first_arg.method == :slice or first_arg.method == :only)
81
+ return
82
+ elsif not node_type? first_arg, :hash
83
+ if attr_protected
84
+ confidence = CONFIDENCE[:med]
85
+ else
86
+ confidence = CONFIDENCE[:high]
87
+ end
88
+ else
89
+ confidence = CONFIDENCE[:low]
90
+ end
91
+ elsif node_type? call.first_arg, :lit, :str
92
+ return
93
+ else
94
+ confidence = CONFIDENCE[:low]
95
+ input = nil
96
+ end
97
+
98
+ warn :result => res,
99
+ :warning_type => "Mass Assignment",
100
+ :warning_code => :mass_assign_call,
101
+ :message => "Unprotected mass assignment",
102
+ :code => call,
103
+ :user_input => input,
104
+ :confidence => confidence
105
+ end
106
+
107
+ res
108
+ end
109
+
110
+ #Want to ignore calls to Model.new that have no arguments
111
+ def check_call call
112
+ process_call_args call
113
+
114
+ if call.method == :update
115
+ arg = call.second_arg
116
+ else
117
+ arg = call.first_arg
118
+ end
119
+
120
+ if arg.nil? #empty new()
121
+ false
122
+ elsif hash? arg and not include_user_input? arg
123
+ false
124
+ elsif all_literal_args? call
125
+ false
126
+ else
127
+ true
128
+ end
129
+ end
130
+
131
+ LITERALS = Set[:lit, :true, :false, :nil, :string]
132
+
133
+ def all_literal_args? exp
134
+ if call? exp
135
+ exp.each_arg do |arg|
136
+ return false unless literal? arg
137
+ end
138
+
139
+ true
140
+ else
141
+ exp.all? do |arg|
142
+ literal? arg
143
+ end
144
+ end
145
+
146
+ end
147
+
148
+ def literal? exp
149
+ if sexp? exp
150
+ if exp.node_type == :hash
151
+ all_literal_args? exp
152
+ else
153
+ LITERALS.include? exp.node_type
154
+ end
155
+ else
156
+ true
157
+ end
158
+ end
159
+
160
+ # Look for and warn about uses of Parameters#permit! for mass assignment
161
+ def check_permit!
162
+ tracker.find_call(:method => :permit!).each do |result|
163
+ if params? result[:call].target and not result[:chain].include? :slice
164
+ warn_on_permit! result
165
+ end
166
+ end
167
+ end
168
+
169
+ # Look for actual use of params in mass assignment to avoid
170
+ # warning about uses of Parameters#permit! without any mass assignment
171
+ # or when mass assignment is restricted by model instead.
172
+ def subsequent_mass_assignment? result
173
+ location = result[:location]
174
+ line = result[:call].line
175
+ find_mass_assign_calls.any? do |call|
176
+ call[:location] == location and
177
+ params? call[:call].first_arg and
178
+ call[:call].line >= line
179
+ end
180
+ end
181
+
182
+ def warn_on_permit! result
183
+ return if duplicate? result or result[:call].original_line
184
+ add_result result
185
+
186
+ confidence = if subsequent_mass_assignment? result
187
+ CONFIDENCE[:high]
188
+ else
189
+ CONFIDENCE[:med]
190
+ end
191
+
192
+ warn :result => result,
193
+ :warning_type => "Mass Assignment",
194
+ :warning_code => :mass_assign_permit!,
195
+ :message => "Parameters should be whitelisted for mass assignment",
196
+ :confidence => confidence
197
+ end
198
+ end