brakeman 3.1.1 → 3.1.2

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +18 -0
  3. data/lib/brakeman.rb +17 -13
  4. data/lib/brakeman/checks/base_check.rb +2 -0
  5. data/lib/brakeman/checks/check_content_tag.rb +2 -2
  6. data/lib/brakeman/checks/check_cross_site_scripting.rb +6 -6
  7. data/lib/brakeman/checks/check_deserialize.rb +1 -1
  8. data/lib/brakeman/checks/check_evaluation.rb +1 -1
  9. data/lib/brakeman/checks/check_execute.rb +3 -5
  10. data/lib/brakeman/checks/check_file_access.rb +1 -1
  11. data/lib/brakeman/checks/check_forgery_setting.rb +2 -1
  12. data/lib/brakeman/checks/check_link_to.rb +2 -2
  13. data/lib/brakeman/checks/check_link_to_href.rb +10 -3
  14. data/lib/brakeman/checks/check_mass_assignment.rb +2 -4
  15. data/lib/brakeman/checks/check_model_attributes.rb +1 -0
  16. data/lib/brakeman/checks/check_model_serialize.rb +2 -1
  17. data/lib/brakeman/checks/check_number_to_currency.rb +0 -1
  18. data/lib/brakeman/checks/check_redirect.rb +1 -1
  19. data/lib/brakeman/checks/check_regex_dos.rb +1 -1
  20. data/lib/brakeman/checks/check_render.rb +1 -1
  21. data/lib/brakeman/checks/check_render_inline.rb +28 -16
  22. data/lib/brakeman/checks/check_select_tag.rb +1 -1
  23. data/lib/brakeman/checks/check_send.rb +1 -1
  24. data/lib/brakeman/checks/check_session_manipulation.rb +1 -1
  25. data/lib/brakeman/checks/check_simple_format.rb +1 -1
  26. data/lib/brakeman/checks/check_sql.rb +2 -2
  27. data/lib/brakeman/checks/check_symbol_dos.rb +1 -1
  28. data/lib/brakeman/checks/check_unsafe_reflection.rb +1 -1
  29. data/lib/brakeman/checks/check_unscoped_find.rb +1 -1
  30. data/lib/brakeman/checks/check_weak_hash.rb +0 -1
  31. data/lib/brakeman/checks/check_without_protection.rb +1 -3
  32. data/lib/brakeman/processors/alias_processor.rb +11 -1
  33. data/lib/brakeman/processors/base_processor.rb +4 -1
  34. data/lib/brakeman/processors/controller_processor.rb +2 -0
  35. data/lib/brakeman/processors/haml_template_processor.rb +1 -1
  36. data/lib/brakeman/processors/lib/processor_helper.rb +13 -0
  37. data/lib/brakeman/processors/library_processor.rb +8 -0
  38. data/lib/brakeman/processors/model_processor.rb +2 -0
  39. data/lib/brakeman/report/report_html.rb +11 -1
  40. data/lib/brakeman/report/templates/controller_overview.html.erb +18 -14
  41. data/lib/brakeman/report/templates/controller_warnings.html.erb +18 -14
  42. data/lib/brakeman/report/templates/error_overview.html.erb +8 -4
  43. data/lib/brakeman/report/templates/header.html.erb +32 -18
  44. data/lib/brakeman/report/templates/ignored_warnings.html.erb +11 -7
  45. data/lib/brakeman/report/templates/model_warnings.html.erb +18 -14
  46. data/lib/brakeman/report/templates/overview.html.erb +32 -28
  47. data/lib/brakeman/report/templates/security_warnings.html.erb +18 -14
  48. data/lib/brakeman/report/templates/template_overview.html.erb +10 -6
  49. data/lib/brakeman/report/templates/view_warnings.html.erb +30 -26
  50. data/lib/brakeman/report/templates/warning_overview.html.erb +12 -8
  51. data/lib/brakeman/tracker/collection.rb +12 -0
  52. data/lib/brakeman/tracker/controller.rb +2 -2
  53. data/lib/brakeman/version.rb +1 -1
  54. data/lib/brakeman/warning.rb +29 -6
  55. data/lib/ruby_parser/bm_sexp.rb +18 -0
  56. metadata +16 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7a5cc8e49df767622714791bc13b5d32717b23e9
4
- data.tar.gz: 433d3fccd753f8f51795e34b2a7d1b6e54387023
3
+ metadata.gz: 4d7d20b349b33016522595eb63c5ef4cc0e257fa
4
+ data.tar.gz: 9dd081fae534c5ffb2f42f63178cdba9b912a27d
5
5
  SHA512:
6
- metadata.gz: 07264b78f6664f20e8a989998b1bac98d2235ab5324d69ba490ca0a49cafd7acf5f999f2a472eaa026a6dc0879059955302a08cb03338f5967acf13a6deebe5d
7
- data.tar.gz: 0c591fe4bc92ec53608dd11dd62592f1ab3f37de5b65c8d76020f6412c19ff816d5f526a74ef4bfe4edabd197c39ababb8824739127c1b1f39db3a4c3a0d359b
6
+ metadata.gz: 889ad360ae4655bfff280157ca45ff548945fa8f3cf6f6d03333f0e04ac107d3489015cd0d837ecb0b0f8ea55fd985243f7d57e87d99d15c0ca76f8d0647ac81
7
+ data.tar.gz: a45beea309a50f727dc2a3d25628b89f5344126d8fc5231ca219fab4e4d601dbaee871bc8008aad006895a221415715ea5b5063bc00c01dedcb65ab012fb14b1
data/CHANGES CHANGED
@@ -1,3 +1,21 @@
1
+ # 3.1.2
2
+
3
+ * Treat `current_user` like a model
4
+ * Set user input value for inline renders
5
+ * Avoid warning on inline renders with safe content types
6
+ * Handle empty interpolation in HAML filters
7
+ * Ignore filters that are not method names
8
+ * Avoid warning about model find/find_by* in hrefs
9
+ * Use SafeYAML to load configuration files
10
+ * Warn on SQL query keys, not values in hashes
11
+ * Allow inspection of recursive Sexps
12
+ * Add line numbers to class-level warnings
13
+ * Handle `private def ...`
14
+ * Catch divide-by-zero in alias processing
15
+ * Reduce string allocations in Warning#initialize
16
+ * Sortable tables in HTML report (David Lanner)
17
+ * Search for config file relative to application root
18
+
1
19
  # 3.1.1
2
20
 
3
21
  * Add optional check for use of MD5 and SHA1
@@ -1,5 +1,5 @@
1
1
  require 'rubygems'
2
- require 'yaml'
2
+ require 'safe_yaml/load'
3
3
  require 'set'
4
4
 
5
5
  module Brakeman
@@ -73,7 +73,7 @@ module Brakeman
73
73
  options.delete :quiet
74
74
  end
75
75
 
76
- options = default_options.merge(load_options(options[:config_file], options[:quiet])).merge(options)
76
+ options = default_options.merge(load_options(options)).merge(options)
77
77
 
78
78
  if options[:quiet].nil? and not command_line
79
79
  options[:quiet] = true
@@ -85,17 +85,15 @@ module Brakeman
85
85
  options
86
86
  end
87
87
 
88
- CONFIG_FILES = [
89
- File.expand_path("./config/brakeman.yml"),
90
- File.expand_path("~/.brakeman/config.yml"),
91
- File.expand_path("/etc/brakeman/config.yml")
92
- ]
93
-
94
88
  #Load options from YAML file
95
- def self.load_options custom_location, quiet
89
+ def self.load_options line_options
90
+ custom_location = line_options[:config_file]
91
+ quiet = line_options[:quiet]
92
+ app_path = line_options[:app_path]
93
+
96
94
  #Load configuration file
97
- if config = config_file(custom_location)
98
- options = YAML.load_file config
95
+ if config = config_file(custom_location, app_path)
96
+ options = SafeYAML.load_file config, :deserialize_symbols => true
99
97
 
100
98
  if options
101
99
  options.each { |k, v| options[k] = Set.new v if v.is_a? Array }
@@ -115,8 +113,14 @@ module Brakeman
115
113
  end
116
114
  end
117
115
 
118
- def self.config_file custom_location = nil
119
- supported_locations = [File.expand_path(custom_location || "")] + CONFIG_FILES
116
+ CONFIG_FILES = [
117
+ File.expand_path("~/.brakeman/config.yml"),
118
+ File.expand_path("/etc/brakeman/config.yml")
119
+ ]
120
+
121
+ def self.config_file custom_location, app_path
122
+ app_config = File.expand_path(File.join(app_path, "config", "brakeman.yml"))
123
+ supported_locations = [File.expand_path(custom_location || ""), app_config] + CONFIG_FILES
120
124
  supported_locations.detect {|f| File.file?(f) }
121
125
  end
122
126
 
@@ -404,6 +404,8 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
404
404
 
405
405
  if exp.is_a? Symbol
406
406
  @models.include? exp
407
+ elsif call? exp and exp.target.nil? and exp.method == :current_user
408
+ true
407
409
  elsif sexp? exp
408
410
  @models.include? class_name(exp)
409
411
  else
@@ -102,7 +102,7 @@ class Brakeman::CheckContentTag < Brakeman::CheckCrossSiteScripting
102
102
  :warning_type => "Cross Site Scripting",
103
103
  :warning_code => :xss_content_tag,
104
104
  :message => message,
105
- :user_input => input.match,
105
+ :user_input => input,
106
106
  :confidence => CONFIDENCE[:high],
107
107
  :link_path => "content_tag"
108
108
 
@@ -136,7 +136,7 @@ class Brakeman::CheckContentTag < Brakeman::CheckCrossSiteScripting
136
136
  :warning_type => "Cross Site Scripting",
137
137
  :warning_code => :xss_content_tag,
138
138
  :message => message,
139
- :user_input => @matched.match,
139
+ :user_input => @matched,
140
140
  :confidence => CONFIDENCE[:med],
141
141
  :link_path => "content_tag"
142
142
  end
@@ -199,7 +199,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
199
199
  :warning_code => warning_code,
200
200
  :message => message,
201
201
  :code => exp,
202
- :user_input => @matched.match,
202
+ :user_input => @matched,
203
203
  :confidence => confidence,
204
204
  :link_path => link_path
205
205
  end
@@ -340,7 +340,7 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
340
340
  def ignore_call? target, method
341
341
  ignored_method?(target, method) or
342
342
  safe_input_attribute?(target, method) or
343
- ignored_model_method?(method) or
343
+ ignored_model_method?(target, method) or
344
344
  form_builder_method?(target, method) or
345
345
  haml_escaped?(target, method) or
346
346
  boolean_method?(method) or
@@ -348,10 +348,10 @@ class Brakeman::CheckCrossSiteScripting < Brakeman::BaseCheck
348
348
  xml_escaped?(target, method)
349
349
  end
350
350
 
351
- def ignored_model_method? method
352
- @matched and
353
- @matched.type == :model and
354
- IGNORE_MODEL_METHODS.include? method
351
+ def ignored_model_method? target, method
352
+ ((@matched and @matched.type == :model) or
353
+ model_name? target) and
354
+ IGNORE_MODEL_METHODS.include? method
355
355
  end
356
356
 
357
357
  def ignored_method? target, method
@@ -49,7 +49,7 @@ class Brakeman::CheckDeserialize < Brakeman::BaseCheck
49
49
  :warning_type => "Remote Code Execution",
50
50
  :warning_code => :unsafe_deserialize,
51
51
  :message => message,
52
- :user_input => input.match,
52
+ :user_input => input,
53
53
  :confidence => confidence,
54
54
  :link_path => "unsafe_deserialization"
55
55
  end
@@ -29,7 +29,7 @@ class Brakeman::CheckEvaluation < Brakeman::BaseCheck
29
29
  :warning_code => :code_eval,
30
30
  :message => "User input in eval",
31
31
  :code => result[:call],
32
- :user_input => input.match,
32
+ :user_input => input,
33
33
  :confidence => CONFIDENCE[:high]
34
34
  end
35
35
  end
@@ -63,7 +63,7 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
63
63
  :warning_code => :command_injection,
64
64
  :message => "Possible command injection",
65
65
  :code => call,
66
- :user_input => failure.match,
66
+ :user_input => failure,
67
67
  :confidence => confidence
68
68
  end
69
69
  end
@@ -75,7 +75,7 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
75
75
  :warning_type => "Command Injection",
76
76
  :warning_code => :command_injection,
77
77
  :message => "Possible command injection in open()",
78
- :user_input => match.match,
78
+ :user_input => match,
79
79
  :confidence => CONFIDENCE[:high]
80
80
  end
81
81
  end
@@ -111,10 +111,8 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
111
111
 
112
112
  if input = include_user_input?(exp)
113
113
  confidence = CONFIDENCE[:high]
114
- user_input = input.match
115
114
  elsif input = dangerous?(exp)
116
115
  confidence = CONFIDENCE[:med]
117
- user_input = input
118
116
  else
119
117
  return
120
118
  end
@@ -124,7 +122,7 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
124
122
  :warning_code => :command_injection,
125
123
  :message => "Possible command injection",
126
124
  :code => exp,
127
- :user_input => user_input,
125
+ :user_input => input,
128
126
  :confidence => confidence
129
127
  end
130
128
 
@@ -57,7 +57,7 @@ class Brakeman::CheckFileAccess < Brakeman::BaseCheck
57
57
  :message => message,
58
58
  :confidence => confidence,
59
59
  :code => call,
60
- :user_input => match.match
60
+ :user_input => match
61
61
  end
62
62
  end
63
63
  end
@@ -28,7 +28,8 @@ class Brakeman::CheckForgerySetting < Brakeman::BaseCheck
28
28
  :warning_code => :csrf_protection_missing,
29
29
  :message => "'protect_from_forgery' should be called in ApplicationController",
30
30
  :confidence => CONFIDENCE[:high],
31
- :file => app_controller.file
31
+ :file => app_controller.file,
32
+ :line => app_controller.top_line
32
33
 
33
34
  elsif version_between? "2.1.0", "2.3.10"
34
35
 
@@ -70,7 +70,7 @@ class Brakeman::CheckLinkTo < Brakeman::CheckCrossSiteScripting
70
70
 
71
71
  message = "Unescaped #{friendly_type_of input} in link_to"
72
72
 
73
- warn_xss(result, message, input.match, CONFIDENCE[:high])
73
+ warn_xss(result, message, input, CONFIDENCE[:high])
74
74
  end
75
75
 
76
76
  # Check if we should warn about the specified method
@@ -93,7 +93,7 @@ class Brakeman::CheckLinkTo < Brakeman::CheckCrossSiteScripting
93
93
 
94
94
  message = "Unescaped #{friendly_type_of matched} in link_to"
95
95
 
96
- warn_xss(result, message, @matched.match, CONFIDENCE[:med])
96
+ warn_xss(result, message, @matched, CONFIDENCE[:med])
97
97
  end
98
98
 
99
99
  # Create a warn for this xss
@@ -51,11 +51,11 @@ class Brakeman::CheckLinkToHref < Brakeman::CheckLinkTo
51
51
  :warning_type => "Cross Site Scripting",
52
52
  :warning_code => :xss_link_to_href,
53
53
  :message => message,
54
- :user_input => input.match,
54
+ :user_input => input,
55
55
  :confidence => CONFIDENCE[:high],
56
56
  :link_path => "link_to_href"
57
57
  end
58
- elsif has_immediate_model? url_arg
58
+ elsif has_immediate_model? url_arg or model_find_call? url_arg
59
59
 
60
60
  # Decided NOT warn on models. polymorphic_path is called it a model is
61
61
  # passed to link_to (which passes it to url_for)
@@ -84,7 +84,7 @@ class Brakeman::CheckLinkToHref < Brakeman::CheckLinkTo
84
84
  :warning_type => "Cross Site Scripting",
85
85
  :warning_code => :xss_link_to_href,
86
86
  :message => message,
87
- :user_input => @matched.match,
87
+ :user_input => @matched,
88
88
  :confidence => CONFIDENCE[:med],
89
89
  :link_path => "link_to_href"
90
90
  end
@@ -105,4 +105,11 @@ class Brakeman::CheckLinkToHref < Brakeman::CheckLinkTo
105
105
  method.to_s =~ /_path$/ or
106
106
  (target.nil? and method.to_s =~ /_url$/)
107
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
108
115
  end
@@ -80,16 +80,14 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck
80
80
  else
81
81
  confidence = CONFIDENCE[:high]
82
82
  end
83
- user_input = input.match
84
83
  else
85
84
  confidence = CONFIDENCE[:low]
86
- user_input = input.match
87
85
  end
88
86
  elsif node_type? call.first_arg, :lit, :str
89
87
  return
90
88
  else
91
89
  confidence = CONFIDENCE[:low]
92
- user_input = nil
90
+ input = nil
93
91
  end
94
92
 
95
93
  warn :result => res,
@@ -97,7 +95,7 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck
97
95
  :warning_code => :mass_assign_call,
98
96
  :message => "Unprotected mass assignment",
99
97
  :code => call,
100
- :user_input => user_input,
98
+ :user_input => input,
101
99
  :confidence => confidence
102
100
  end
103
101
 
@@ -56,6 +56,7 @@ class Brakeman::CheckModelAttributes < Brakeman::BaseCheck
56
56
  if model.attr_protected.nil?
57
57
  warn :model => name,
58
58
  :file => model.file,
59
+ :line => model.top_line,
59
60
  :warning_type => "Attribute Restriction",
60
61
  :warning_code => :no_attr_accessible,
61
62
  :message => "Mass assignment is not restricted using attr_accessible",
@@ -60,7 +60,8 @@ class Brakeman::CheckModelSerialize < Brakeman::BaseCheck
60
60
  :message => "Serialized attributes are vulnerable in Rails #{rails_version}, upgrade to #{@upgrade_version} or patch.",
61
61
  :confidence => confidence,
62
62
  :link => "https://groups.google.com/d/topic/rubyonrails-security/KtmwSbEpzrU/discussion",
63
- :file => model.file
63
+ :file => model.file,
64
+ :line => model.top_line
64
65
  end
65
66
  end
66
67
  end
@@ -50,7 +50,6 @@ class Brakeman::CheckNumberToCurrency < Brakeman::BaseCheck
50
50
 
51
51
  def check_helper_option result, exp
52
52
  if match = (has_immediate_user_input? exp or has_immediate_model? exp)
53
- match = match.match if match.is_a? Match
54
53
  warn_on_number_helper result, match
55
54
  @found_any = true
56
55
  else
@@ -53,7 +53,7 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
53
53
  :warning_code => :open_redirect,
54
54
  :message => "Possible unprotected redirect",
55
55
  :code => call,
56
- :user_input => res.match,
56
+ :user_input => res,
57
57
  :confidence => confidence
58
58
  end
59
59
  end
@@ -52,7 +52,7 @@ class Brakeman::CheckRegexDoS < Brakeman::BaseCheck
52
52
  :warning_code => :regex_dos,
53
53
  :message => message,
54
54
  :confidence => confidence,
55
- :user_input => match.match
55
+ :user_input => match
56
56
  end
57
57
  end
58
58
  end
@@ -55,7 +55,7 @@ class Brakeman::CheckRender < Brakeman::BaseCheck
55
55
  :warning_type => "Dynamic Render Path",
56
56
  :warning_code => :dynamic_render_path,
57
57
  :message => message,
58
- :user_input => input.match,
58
+ :user_input => input,
59
59
  :confidence => confidence
60
60
  end
61
61
  end
@@ -20,23 +20,35 @@ class Brakeman::CheckRenderInline < Brakeman::CheckCrossSiteScripting
20
20
  if node_type? call, :render and
21
21
  (call.render_type == :text or call.render_type == :inline)
22
22
 
23
- render_value = call[2]
24
-
25
- if input = has_immediate_user_input?(render_value)
26
- warn :result => result,
27
- :warning_type => "Cross Site Scripting",
28
- :warning_code => :cross_site_scripting_inline,
29
- :message => "Unescaped #{friendly_type_of input} rendered inline",
30
- :code => input.match,
31
- :confidence => CONFIDENCE[:high]
32
- elsif input = has_immediate_model?(render_value)
33
- warn :result => result,
34
- :warning_type => "Cross Site Scripting",
35
- :warning_code => :cross_site_scripting_inline,
36
- :message => "Unescaped model attribute rendered inline",
37
- :code => input,
38
- :confidence => CONFIDENCE[:med]
23
+ unless call.render_type == :text and content_type_set? call[3]
24
+ render_value = call[2]
25
+
26
+ if input = has_immediate_user_input?(render_value)
27
+ warn :result => result,
28
+ :warning_type => "Cross Site Scripting",
29
+ :warning_code => :cross_site_scripting_inline,
30
+ :message => "Unescaped #{friendly_type_of input} rendered inline",
31
+ :user_input => input,
32
+ :confidence => CONFIDENCE[:high]
33
+ elsif input = has_immediate_model?(render_value)
34
+ warn :result => result,
35
+ :warning_type => "Cross Site Scripting",
36
+ :warning_code => :cross_site_scripting_inline,
37
+ :message => "Unescaped model attribute rendered inline",
38
+ :user_input => input,
39
+ :confidence => CONFIDENCE[:med]
40
+ end
39
41
  end
40
42
  end
41
43
  end
44
+
45
+ CONTENT_TYPES = ["text/html", "text/javascript", "application/javascript"]
46
+
47
+ def content_type_set? opts
48
+ if hash? opts
49
+ content_type = hash_access(opts, :content_type)
50
+
51
+ string? content_type and not CONTENT_TYPES.include? content_type.value
52
+ end
53
+ end
42
54
  end
@@ -52,7 +52,7 @@ class Brakeman::CheckSelectTag < Brakeman::BaseCheck
52
52
  :result => result,
53
53
  :message => @message,
54
54
  :confidence => CONFIDENCE[:high],
55
- :user_input => input.match,
55
+ :user_input => input,
56
56
  :link_path => "https://groups.google.com/d/topic/rubyonrails-security/fV3QUToSMSw/discussion"
57
57
  end
58
58
  end
@@ -30,7 +30,7 @@ class Brakeman::CheckSend < Brakeman::BaseCheck
30
30
  :warning_code => :dangerous_send,
31
31
  :message => "User controlled method execution",
32
32
  :code => result[:call],
33
- :user_input => input.match,
33
+ :user_input => input,
34
34
  :confidence => CONFIDENCE[:high]
35
35
  end
36
36
  end
@@ -29,7 +29,7 @@ class Brakeman::CheckSessionManipulation < Brakeman::BaseCheck
29
29
  :warning_code => :session_key_manipulation,
30
30
  :message => "#{friendly_type_of(input).capitalize} used as key in session hash",
31
31
  :code => result[:call],
32
- :user_input => input.match,
32
+ :user_input => input,
33
33
  :confidence => confidence
34
34
  end
35
35
  end