brakeman-min 0.5.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) hide show
  1. data/CHANGES +529 -0
  2. data/README.md +74 -28
  3. data/bin/brakeman +60 -266
  4. data/lib/brakeman.rb +422 -0
  5. data/lib/brakeman/app_tree.rb +101 -0
  6. data/lib/brakeman/brakeman.rake +10 -0
  7. data/lib/brakeman/call_index.rb +215 -0
  8. data/lib/brakeman/checks.rb +180 -0
  9. data/lib/brakeman/checks/base_check.rb +538 -0
  10. data/lib/brakeman/checks/check_basic_auth.rb +89 -0
  11. data/lib/brakeman/checks/check_content_tag.rb +162 -0
  12. data/lib/brakeman/checks/check_cross_site_scripting.rb +334 -0
  13. data/lib/{checks → brakeman/checks}/check_default_routes.rb +13 -6
  14. data/lib/brakeman/checks/check_deserialize.rb +57 -0
  15. data/lib/brakeman/checks/check_digest_dos.rb +38 -0
  16. data/lib/brakeman/checks/check_escape_function.rb +21 -0
  17. data/lib/brakeman/checks/check_evaluation.rb +33 -0
  18. data/lib/brakeman/checks/check_execute.rb +98 -0
  19. data/lib/brakeman/checks/check_file_access.rb +62 -0
  20. data/lib/brakeman/checks/check_filter_skipping.rb +31 -0
  21. data/lib/brakeman/checks/check_forgery_setting.rb +54 -0
  22. data/lib/brakeman/checks/check_jruby_xml.rb +38 -0
  23. data/lib/brakeman/checks/check_json_parsing.rb +102 -0
  24. data/lib/brakeman/checks/check_link_to.rb +132 -0
  25. data/lib/brakeman/checks/check_link_to_href.rb +92 -0
  26. data/lib/{checks → brakeman/checks}/check_mail_to.rb +14 -13
  27. data/lib/brakeman/checks/check_mass_assignment.rb +143 -0
  28. data/lib/brakeman/checks/check_model_attr_accessible.rb +48 -0
  29. data/lib/brakeman/checks/check_model_attributes.rb +118 -0
  30. data/lib/brakeman/checks/check_model_serialize.rb +66 -0
  31. data/lib/{checks → brakeman/checks}/check_nested_attributes.rb +10 -6
  32. data/lib/brakeman/checks/check_quote_table_name.rb +40 -0
  33. data/lib/brakeman/checks/check_redirect.rb +177 -0
  34. data/lib/brakeman/checks/check_render.rb +62 -0
  35. data/lib/brakeman/checks/check_response_splitting.rb +21 -0
  36. data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +31 -0
  37. data/lib/brakeman/checks/check_sanitize_methods.rb +54 -0
  38. data/lib/brakeman/checks/check_select_tag.rb +60 -0
  39. data/lib/brakeman/checks/check_select_vulnerability.rb +58 -0
  40. data/lib/brakeman/checks/check_send.rb +35 -0
  41. data/lib/brakeman/checks/check_send_file.rb +19 -0
  42. data/lib/brakeman/checks/check_session_settings.rb +145 -0
  43. data/lib/brakeman/checks/check_single_quotes.rb +101 -0
  44. data/lib/brakeman/checks/check_skip_before_filter.rb +62 -0
  45. data/lib/brakeman/checks/check_sql.rb +577 -0
  46. data/lib/brakeman/checks/check_strip_tags.rb +64 -0
  47. data/lib/brakeman/checks/check_symbol_dos.rb +67 -0
  48. data/lib/brakeman/checks/check_translate_bug.rb +45 -0
  49. data/lib/brakeman/checks/check_unsafe_reflection.rb +51 -0
  50. data/lib/brakeman/checks/check_validation_regex.rb +88 -0
  51. data/lib/brakeman/checks/check_without_protection.rb +64 -0
  52. data/lib/brakeman/checks/check_yaml_parsing.rb +121 -0
  53. data/lib/brakeman/differ.rb +66 -0
  54. data/lib/{format → brakeman/format}/style.css +28 -0
  55. data/lib/brakeman/options.rb +256 -0
  56. data/lib/brakeman/parsers/rails2_erubis.rb +6 -0
  57. data/lib/brakeman/parsers/rails2_xss_plugin_erubis.rb +48 -0
  58. data/lib/{scanner_erubis.rb → brakeman/parsers/rails3_erubis.rb} +8 -21
  59. data/lib/brakeman/processor.rb +102 -0
  60. data/lib/brakeman/processors/alias_processor.rb +780 -0
  61. data/lib/{processors → brakeman/processors}/base_processor.rb +90 -74
  62. data/lib/brakeman/processors/config_processor.rb +14 -0
  63. data/lib/brakeman/processors/controller_alias_processor.rb +334 -0
  64. data/lib/brakeman/processors/controller_processor.rb +265 -0
  65. data/lib/{processors → brakeman/processors}/erb_template_processor.rb +21 -19
  66. data/lib/brakeman/processors/erubis_template_processor.rb +96 -0
  67. data/lib/brakeman/processors/gem_processor.rb +59 -0
  68. data/lib/{processors → brakeman/processors}/haml_template_processor.rb +26 -21
  69. data/lib/brakeman/processors/lib/find_all_calls.rb +185 -0
  70. data/lib/{processors → brakeman/processors}/lib/find_call.rb +23 -28
  71. data/lib/brakeman/processors/lib/find_return_value.rb +134 -0
  72. data/lib/brakeman/processors/lib/processor_helper.rb +82 -0
  73. data/lib/{processors/config_processor.rb → brakeman/processors/lib/rails2_config_processor.rb} +32 -35
  74. data/lib/{processors → brakeman/processors}/lib/rails2_route_processor.rb +60 -52
  75. data/lib/brakeman/processors/lib/rails3_config_processor.rb +129 -0
  76. data/lib/brakeman/processors/lib/rails3_route_processor.rb +282 -0
  77. data/lib/{processors → brakeman/processors}/lib/render_helper.rb +54 -20
  78. data/lib/brakeman/processors/lib/route_helper.rb +62 -0
  79. data/lib/{processors → brakeman/processors}/library_processor.rb +24 -17
  80. data/lib/{processors → brakeman/processors}/model_processor.rb +46 -22
  81. data/lib/{processors → brakeman/processors}/output_processor.rb +34 -40
  82. data/lib/brakeman/processors/route_processor.rb +17 -0
  83. data/lib/brakeman/processors/slim_template_processor.rb +113 -0
  84. data/lib/brakeman/processors/template_alias_processor.rb +120 -0
  85. data/lib/{processors → brakeman/processors}/template_processor.rb +10 -7
  86. data/lib/brakeman/report.rb +68 -0
  87. data/lib/brakeman/report/ignore/config.rb +130 -0
  88. data/lib/brakeman/report/ignore/interactive.rb +311 -0
  89. data/lib/brakeman/report/initializers/faster_csv.rb +7 -0
  90. data/lib/brakeman/report/initializers/multi_json.rb +29 -0
  91. data/lib/brakeman/report/renderer.rb +24 -0
  92. data/lib/brakeman/report/report_base.rb +279 -0
  93. data/lib/brakeman/report/report_csv.rb +56 -0
  94. data/lib/brakeman/report/report_hash.rb +22 -0
  95. data/lib/brakeman/report/report_html.rb +203 -0
  96. data/lib/brakeman/report/report_json.rb +46 -0
  97. data/lib/brakeman/report/report_table.rb +109 -0
  98. data/lib/brakeman/report/report_tabs.rb +17 -0
  99. data/lib/brakeman/report/templates/controller_overview.html.erb +18 -0
  100. data/lib/brakeman/report/templates/controller_warnings.html.erb +17 -0
  101. data/lib/brakeman/report/templates/error_overview.html.erb +25 -0
  102. data/lib/brakeman/report/templates/header.html.erb +44 -0
  103. data/lib/brakeman/report/templates/ignored_warnings.html.erb +21 -0
  104. data/lib/brakeman/report/templates/model_warnings.html.erb +17 -0
  105. data/lib/brakeman/report/templates/overview.html.erb +34 -0
  106. data/lib/brakeman/report/templates/security_warnings.html.erb +19 -0
  107. data/lib/brakeman/report/templates/template_overview.html.erb +17 -0
  108. data/lib/brakeman/report/templates/view_warnings.html.erb +30 -0
  109. data/lib/brakeman/report/templates/warning_overview.html.erb +13 -0
  110. data/lib/brakeman/rescanner.rb +446 -0
  111. data/lib/brakeman/scanner.rb +362 -0
  112. data/lib/brakeman/tracker.rb +296 -0
  113. data/lib/brakeman/util.rb +413 -0
  114. data/lib/brakeman/version.rb +3 -0
  115. data/lib/brakeman/warning.rb +217 -0
  116. data/lib/brakeman/warning_codes.rb +68 -0
  117. data/lib/ruby_parser/bm_sexp.rb +562 -0
  118. data/lib/ruby_parser/bm_sexp_processor.rb +230 -0
  119. metadata +152 -66
  120. data/lib/checks.rb +0 -71
  121. data/lib/checks/base_check.rb +0 -357
  122. data/lib/checks/check_cross_site_scripting.rb +0 -336
  123. data/lib/checks/check_evaluation.rb +0 -27
  124. data/lib/checks/check_execute.rb +0 -110
  125. data/lib/checks/check_file_access.rb +0 -46
  126. data/lib/checks/check_forgery_setting.rb +0 -42
  127. data/lib/checks/check_mass_assignment.rb +0 -74
  128. data/lib/checks/check_model_attributes.rb +0 -36
  129. data/lib/checks/check_redirect.rb +0 -98
  130. data/lib/checks/check_render.rb +0 -65
  131. data/lib/checks/check_send_file.rb +0 -15
  132. data/lib/checks/check_session_settings.rb +0 -79
  133. data/lib/checks/check_sql.rb +0 -146
  134. data/lib/checks/check_validation_regex.rb +0 -60
  135. data/lib/processor.rb +0 -86
  136. data/lib/processors/alias_processor.rb +0 -384
  137. data/lib/processors/controller_alias_processor.rb +0 -237
  138. data/lib/processors/controller_processor.rb +0 -202
  139. data/lib/processors/erubis_template_processor.rb +0 -85
  140. data/lib/processors/lib/find_model_call.rb +0 -39
  141. data/lib/processors/lib/processor_helper.rb +0 -36
  142. data/lib/processors/lib/rails3_route_processor.rb +0 -184
  143. data/lib/processors/lib/route_helper.rb +0 -34
  144. data/lib/processors/params_processor.rb +0 -77
  145. data/lib/processors/route_processor.rb +0 -11
  146. data/lib/processors/template_alias_processor.rb +0 -86
  147. data/lib/report.rb +0 -680
  148. data/lib/scanner.rb +0 -227
  149. data/lib/tracker.rb +0 -144
  150. data/lib/util.rb +0 -141
  151. data/lib/version.rb +0 -1
  152. data/lib/warning.rb +0 -99
@@ -0,0 +1,48 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ # Author: Paul Deardorff (themetric)
4
+ # Checks models to see if important foreign keys
5
+ # or attributes are exposed as attr_accessible when
6
+ # they probably shouldn't be.
7
+
8
+ class Brakeman::CheckModelAttrAccessible < Brakeman::BaseCheck
9
+ Brakeman::Checks.add self
10
+
11
+ @description = "Reports models which have dangerous attributes defined under the attr_accessible whitelist."
12
+
13
+ SUSP_ATTRS = {
14
+ /admin/ => CONFIDENCE[:high], # Very dangerous unless some Rails authorization used
15
+ /role/ => CONFIDENCE[:med],
16
+ /banned/ => CONFIDENCE[:med],
17
+ :account_id => CONFIDENCE[:high],
18
+ /\S*_id(s?)\z/ => CONFIDENCE[:low] # All other foreign keys have weak/low confidence
19
+ }
20
+
21
+ def run_check
22
+ check_models do |name, model|
23
+ accessible_attrs = model[:attr_accessible]
24
+ accessible_attrs.each do |attribute|
25
+ SUSP_ATTRS.each do |susp_attr, confidence|
26
+ if susp_attr.is_a?(Regexp) and susp_attr =~ attribute.to_s or susp_attr == attribute
27
+ warn :model => name,
28
+ :file => model[:file],
29
+ :warning_type => "Mass Assignment",
30
+ :warning_code => :mass_assign_call,
31
+ :message => "Potentially dangerous attribute #{attribute} available for mass assignment.",
32
+ :confidence => confidence
33
+ break # Prevent from matching single attr multiple times
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ def check_models
41
+ tracker.models.each do |name, model|
42
+ if !model[:attr_accessible].nil?
43
+ yield name, model
44
+ end
45
+ end
46
+ end
47
+
48
+ end
@@ -0,0 +1,118 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ #Check if mass assignment is used with models
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
+ class Brakeman::CheckModelAttributes < Brakeman::BaseCheck
9
+ Brakeman::Checks.add self
10
+
11
+ @description = "Reports models which do not use attr_restricted and warns on models that use attr_protected"
12
+
13
+ def run_check
14
+ return if mass_assign_disabled?
15
+
16
+ #Roll warnings into one warning for all models
17
+ if tracker.options[:collapse_mass_assignment]
18
+ no_accessible_names = []
19
+ protected_names = []
20
+
21
+ check_models do |name, model|
22
+ if model[:options][: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
28
+
29
+ unless no_accessible_names.empty?
30
+ warn :model => no_accessible_names.sort.join(", "),
31
+ :warning_type => "Attribute Restriction",
32
+ :warning_code => :no_attr_accessible,
33
+ :message => "Mass assignment is not restricted using attr_accessible",
34
+ :confidence => CONFIDENCE[:high]
35
+ end
36
+
37
+ unless protected_names.empty?
38
+ message, confidence, link = check_for_attr_protected_bypass
39
+
40
+ if link
41
+ warning_code = :CVE_2013_0276
42
+ else
43
+ warning_code = :attr_protected_used
44
+ end
45
+
46
+ warn :model => protected_names.sort.join(", "),
47
+ :warning_type => "Attribute Restriction",
48
+ :warning_code => warning_code,
49
+ :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[:options][:attr_protected].nil?
57
+ warn :model => name,
58
+ :file => model[:file],
59
+ :warning_type => "Attribute Restriction",
60
+ :warning_code => :no_attr_accessible,
61
+ :message => "Mass assignment is not restricted using attr_accessible",
62
+ :confidence => CONFIDENCE[:high]
63
+ elsif not tracker.options[:ignore_attr_protected]
64
+ message, confidence, link = check_for_attr_protected_bypass
65
+
66
+ if link
67
+ warning_code = :CVE_2013_0276
68
+ else
69
+ warning_code = :attr_protected_used
70
+ end
71
+
72
+ warn :model => name,
73
+ :file => model[:file],
74
+ :line => model[:options][:attr_protected].first.line,
75
+ :warning_type => "Attribute Restriction",
76
+ :warning_code => warning_code,
77
+ :message => message,
78
+ :confidence => confidence
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ def check_models
85
+ tracker.models.each do |name, model|
86
+ if unprotected_model? model
87
+ yield name, model
88
+ end
89
+ end
90
+ end
91
+
92
+ def check_for_attr_protected_bypass
93
+ upgrade_version = case
94
+ when version_between?("2.0.0", "2.3.16")
95
+ "2.3.17"
96
+ when version_between?("3.0.0", "3.0.99")
97
+ "3.2.11"
98
+ when version_between?("3.1.0", "3.1.10")
99
+ "3.1.11"
100
+ when version_between?("3.2.0", "3.2.11")
101
+ "3.2.12"
102
+ else
103
+ nil
104
+ end
105
+
106
+ if upgrade_version
107
+ message = "attr_protected is bypassable in #{tracker.config[:rails_version]}, use attr_accessible or upgrade to #{upgrade_version}"
108
+ confidence = CONFIDENCE[:high]
109
+ link = "https://groups.google.com/d/topic/rubyonrails-security/AFBKNY7VSH8/discussion"
110
+ else
111
+ message = "attr_accessible is recommended over attr_protected"
112
+ confidence = CONFIDENCE[:med]
113
+ link = nil
114
+ end
115
+
116
+ return message, confidence, link
117
+ end
118
+ end
@@ -0,0 +1,66 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckModelSerialize < Brakeman::BaseCheck
4
+ Brakeman::Checks.add self
5
+
6
+ @description = "Report uses of serialize in versions vulnerable to CVE-2013-0277"
7
+
8
+ def run_check
9
+ @upgrade_version = case
10
+ when version_between?("2.0.0", "2.3.16")
11
+ "2.3.17"
12
+ when version_between?("3.0.0", "3.0.99")
13
+ "3.2.11"
14
+ else
15
+ nil
16
+ end
17
+
18
+ return unless @upgrade_version
19
+
20
+ tracker.models.each do |name, model|
21
+ check_for_serialize model
22
+ end
23
+ end
24
+
25
+ #High confidence warning on serialized, unprotected attributes.
26
+ #Medium confidence warning for serialized, protected attributes.
27
+ def check_for_serialize model
28
+ if serialized_attrs = model[:options] && model[:options][:serialize]
29
+ attrs = Set.new
30
+
31
+ serialized_attrs.each do |arglist|
32
+ arglist.each do |arg|
33
+ attrs << arg if symbol? arg
34
+ end
35
+ end
36
+
37
+ if unsafe_attrs = model[:attr_accessible]
38
+ attrs.delete_if { |attr| not unsafe_attrs.include? attr.value }
39
+ elsif protected_attrs = model[:options][:attr_protected]
40
+ safe_attrs = Set.new
41
+
42
+ protected_attrs.each do |arglist|
43
+ arglist.each do |arg|
44
+ safe_attrs << arg if symbol? arg
45
+ end
46
+ end
47
+
48
+ attrs.delete_if { |attr| safe_attrs.include? attr }
49
+ end
50
+
51
+ if attrs.empty?
52
+ confidence = CONFIDENCE[:med]
53
+ else
54
+ confidence = CONFIDENCE[:high]
55
+ end
56
+
57
+ warn :model => model[:name],
58
+ :warning_type => "Remote Code Execution",
59
+ :warning_code => :CVE_2013_0277,
60
+ :message => "Serialized attributes are vulnerable in Rails #{tracker.config[:rails_version]}, upgrade to #{@upgrade_version} or patch.",
61
+ :confidence => confidence,
62
+ :link => "https://groups.google.com/d/topic/rubyonrails-security/KtmwSbEpzrU/discussion",
63
+ :file => model[:file]
64
+ end
65
+ end
66
+ end
@@ -1,10 +1,11 @@
1
- require 'checks/base_check'
2
- require 'processors/lib/find_call'
1
+ require 'brakeman/checks/base_check'
3
2
 
4
3
  #Check for vulnerability in nested attributes in Rails 2.3.9 and 3.0.0
5
4
  #http://groups.google.com/group/rubyonrails-security/browse_thread/thread/f9f913d328dafe0c
6
- class CheckNestedAttributes < BaseCheck
7
- Checks.add self
5
+ class Brakeman::CheckNestedAttributes < Brakeman::BaseCheck
6
+ Brakeman::Checks.add self
7
+
8
+ @description = "Checks for nested attributes vulnerability in Rails 2.3.9 and 3.0.0"
8
9
 
9
10
  def run_check
10
11
  version = tracker.config[:rails_version]
@@ -19,13 +20,16 @@ class CheckNestedAttributes < BaseCheck
19
20
  end
20
21
 
21
22
  warn :warning_type => "Nested Attributes",
23
+ :warning_code => :CVE_2010_3933,
22
24
  :message => message,
23
- :confidence => CONFIDENCE[:high]
25
+ :confidence => CONFIDENCE[:high],
26
+ :file => gemfile_or_environment,
27
+ :link_path => "https://groups.google.com/d/topic/rubyonrails-security/-fkT0yja_gw/discussion"
24
28
  end
25
29
  end
26
30
 
27
31
  def uses_nested_attributes?
28
- tracker.models.each do |name, model|
32
+ active_record_models.each do |name, model|
29
33
  return true if model[:options][:accepts_nested_attributes_for]
30
34
  end
31
35
 
@@ -0,0 +1,40 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ #Check for uses of quote_table_name in Rails versions before 2.3.13 and 3.0.10
4
+ #http://groups.google.com/group/rubyonrails-security/browse_thread/thread/6a1e473744bc389b
5
+ class Brakeman::CheckQuoteTableName < Brakeman::BaseCheck
6
+ Brakeman::Checks.add self
7
+
8
+ @description = "Checks for quote_table_name vulnerability in versions before 2.3.14 and 3.0.10"
9
+
10
+ def run_check
11
+ if (version_between?('2.0.0', '2.3.13') or
12
+ version_between?('3.0.0', '3.0.9'))
13
+
14
+ if uses_quote_table_name?
15
+ confidence = CONFIDENCE[:high]
16
+ else
17
+ confidence = CONFIDENCE[:med]
18
+ end
19
+
20
+ if tracker.config[:rails_version] =~ /^3/
21
+ message = "Versions before 3.0.10 have a vulnerability in quote_table_name: CVE-2011-2930"
22
+ else
23
+ message = "Versions before 2.3.14 have a vulnerability in quote_table_name: CVE-2011-2930"
24
+ end
25
+
26
+ warn :warning_type => "SQL Injection",
27
+ :warning_code => :CVE_2011_2930,
28
+ :message => message,
29
+ :confidence => confidence,
30
+ :file => gemfile_or_environment,
31
+ :link_path => "https://groups.google.com/d/topic/rubyonrails-security/ah5HN0S8OJs/discussion"
32
+ end
33
+ end
34
+
35
+ def uses_quote_table_name?
36
+ Brakeman.debug "Finding calls to quote_table_name()"
37
+
38
+ not tracker.find_call(:target => false, :method => :quote_table_name).empty?
39
+ end
40
+ end
@@ -0,0 +1,177 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ #Reports any calls to +redirect_to+ which include parameters in the arguments.
4
+ #
5
+ #For example:
6
+ #
7
+ # redirect_to params.merge(:action => :elsewhere)
8
+ class Brakeman::CheckRedirect < Brakeman::BaseCheck
9
+ Brakeman::Checks.add self
10
+
11
+ @description = "Looks for calls to redirect_to with user input as arguments"
12
+
13
+ def run_check
14
+ Brakeman.debug "Finding calls to redirect_to()"
15
+
16
+ @model_find_calls = Set[:all, :find, :find_by_sql, :first, :last, :new]
17
+
18
+ if tracker.options[:rails3]
19
+ @model_find_calls.merge [:from, :group, :having, :joins, :lock, :order, :reorder, :select, :where]
20
+ end
21
+
22
+ @tracker.find_call(:target => false, :method => :redirect_to).each do |res|
23
+ process_result res
24
+ end
25
+ end
26
+
27
+ def process_result result
28
+ return if duplicate? result
29
+
30
+ call = result[:call]
31
+
32
+ method = call.method
33
+
34
+ if method == :redirect_to and not only_path?(call) and res = include_user_input?(call)
35
+ add_result result
36
+
37
+ if res.type == :immediate
38
+ confidence = CONFIDENCE[:high]
39
+ else
40
+ confidence = CONFIDENCE[:low]
41
+ end
42
+
43
+ warn :result => result,
44
+ :warning_type => "Redirect",
45
+ :warning_code => :open_redirect,
46
+ :message => "Possible unprotected redirect",
47
+ :code => call,
48
+ :user_input => res.match,
49
+ :confidence => confidence
50
+ end
51
+ end
52
+
53
+ #Custom check for user input. First looks to see if the user input
54
+ #is being output directly. This is necessary because of tracker.options[:check_arguments]
55
+ #which can be used to enable/disable reporting output of method calls which use
56
+ #user input as arguments.
57
+ def include_user_input? call, immediate = :immediate
58
+ Brakeman.debug "Checking if call includes user input"
59
+
60
+ arg = call.first_arg
61
+
62
+ # if the first argument is an array, rails assumes you are building a
63
+ # polymorphic route, which will never jump off-host
64
+ return false if array? arg
65
+
66
+ if tracker.options[:ignore_redirect_to_model]
67
+ if model_instance?(arg) or decorated_model?(arg)
68
+ return false
69
+ end
70
+ end
71
+
72
+ if res = has_immediate_model?(arg)
73
+ return Match.new(immediate, res)
74
+ elsif call? arg
75
+ if request_value? arg
76
+ return Match.new(immediate, arg)
77
+ elsif request_value? arg.target
78
+ return Match.new(immediate, arg.target)
79
+ elsif arg.method == :url_for and include_user_input? arg
80
+ return Match.new(immediate, arg)
81
+ #Ignore helpers like some_model_url?
82
+ elsif arg.method.to_s =~ /_(url|path)\z/
83
+ return false
84
+ end
85
+ elsif request_value? arg
86
+ return Match.new(immediate, arg)
87
+ end
88
+
89
+ if tracker.options[:check_arguments] and call? arg
90
+ include_user_input? arg, false #I'm doubting if this is really necessary...
91
+ else
92
+ false
93
+ end
94
+ end
95
+
96
+ #Checks +redirect_to+ arguments for +only_path => true+ which essentially
97
+ #nullifies the danger posed by redirecting with user input
98
+ def only_path? call
99
+ arg = call.first_arg
100
+
101
+ if hash? arg
102
+ if value = hash_access(arg, :only_path)
103
+ return true if true?(value)
104
+ end
105
+ elsif call? arg and arg.method == :url_for
106
+ return check_url_for(arg)
107
+ end
108
+
109
+ false
110
+ end
111
+
112
+ #+url_for+ is only_path => true by default. This checks to see if it is
113
+ #set to false for some reason.
114
+ def check_url_for call
115
+ arg = call.first_arg
116
+
117
+ if hash? arg
118
+ if value = hash_access(arg, :only_path)
119
+ return false if false?(value)
120
+ end
121
+ end
122
+
123
+ true
124
+ end
125
+
126
+ #Returns true if exp is (probably) a model instance
127
+ def model_instance? exp
128
+ if node_type? exp, :or
129
+ model_instance? exp.lhs or model_instance? exp.rhs
130
+ elsif call? exp
131
+ if model_name? exp.target and
132
+ (@model_find_calls.include? exp.method or exp.method.to_s.match(/^find_by_/))
133
+ true
134
+ else
135
+ association?(exp.target, exp.method)
136
+ end
137
+ end
138
+ end
139
+
140
+ #Returns true if exp is (probably) a decorated model instance
141
+ #using the Draper gem
142
+ def decorated_model? exp
143
+ if node_type? exp, :or
144
+ decorated_model? exp.lhs or decorated_model? exp.rhs
145
+ else
146
+ tracker.config[:gems] and
147
+ tracker.config[:gems][:draper] and
148
+ call? exp and
149
+ node_type?(exp.target, :const) and
150
+ exp.target.value.to_s.match(/Decorator$/) and
151
+ exp.method == :decorate
152
+ end
153
+ end
154
+
155
+ #Check if method is actually an association in a Model
156
+ def association? model_name, meth
157
+ if call? model_name
158
+ return association? model_name.target, meth
159
+ elsif model_name? model_name
160
+ model = tracker.models[class_name(model_name)]
161
+ else
162
+ return false
163
+ end
164
+
165
+ return false unless model
166
+
167
+ model[:associations].each do |name, args|
168
+ args.each do |arg|
169
+ if symbol? arg and arg.value == meth
170
+ return true
171
+ end
172
+ end
173
+ end
174
+
175
+ false
176
+ end
177
+ end