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
@@ -54,6 +54,6 @@ class Brakeman::CheckSimpleFormat < Brakeman::CheckCrossSiteScripting
54
54
  :message => "Values passed to simple_format are not safe in Rails #{rails_version}",
55
55
  :confidence => CONFIDENCE[:high],
56
56
  :link_path => "https://groups.google.com/d/msg/ruby-security-ann/5ZI1-H5OoIM/ZNq4FoR2GnIJ",
57
- :user_input => match.match
57
+ :user_input => match
58
58
  end
59
59
  end
@@ -197,7 +197,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
197
197
  input = include_user_input? dangerous_value
198
198
  if input
199
199
  confidence = CONFIDENCE[:high]
200
- user_input = input.match
200
+ user_input = input
201
201
  else
202
202
  confidence = CONFIDENCE[:med]
203
203
  user_input = dangerous_value
@@ -342,7 +342,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
342
342
  def check_hash_keys exp
343
343
  hash_iterate(exp) do |key, value|
344
344
  unless symbol?(key)
345
- unsafe_key = unsafe_sql? value
345
+ unsafe_key = unsafe_sql? key
346
346
  return unsafe_key if unsafe_key
347
347
  end
348
348
  end
@@ -41,7 +41,7 @@ class Brakeman::CheckSymbolDoS < Brakeman::BaseCheck
41
41
  :warning_type => "Denial of Service",
42
42
  :warning_code => :unsafe_symbol_creation,
43
43
  :message => message,
44
- :user_input => input.match,
44
+ :user_input => input,
45
45
  :confidence => confidence
46
46
  end
47
47
  end
@@ -44,7 +44,7 @@ class Brakeman::CheckUnsafeReflection < Brakeman::BaseCheck
44
44
  :warning_type => "Remote Code Execution",
45
45
  :warning_code => :unsafe_constantize,
46
46
  :message => message,
47
- :user_input => input.match,
47
+ :user_input => input,
48
48
  :confidence => confidence
49
49
  end
50
50
  end
@@ -36,6 +36,6 @@ class Brakeman::CheckUnscopedFind < Brakeman::BaseCheck
36
36
  :message => "Unscoped call to #{result[:target]}##{result[:method]}",
37
37
  :code => result[:call],
38
38
  :confidence => CONFIDENCE[:low],
39
- :user_input => input.match
39
+ :user_input => input
40
40
  end
41
41
  end
@@ -30,7 +30,6 @@ class Brakeman::CheckWeakHash < Brakeman::BaseCheck
30
30
 
31
31
  if DIGEST_CALLS.include? call.method
32
32
  if input = user_input_as_arg?(call)
33
- input = input.match
34
33
  confidence = CONFIDENCE[:high]
35
34
  elsif input = hashing_password?(call)
36
35
  confidence = CONFIDENCE[:high]
@@ -43,10 +43,8 @@ class Brakeman::CheckWithoutProtection < Brakeman::BaseCheck
43
43
 
44
44
  if input = include_user_input?(call.arglist)
45
45
  confidence = CONFIDENCE[:high]
46
- user_input = input.match
47
46
  else
48
47
  confidence = CONFIDENCE[:med]
49
- user_input = nil
50
48
  end
51
49
 
52
50
  warn :result => res,
@@ -54,7 +52,7 @@ class Brakeman::CheckWithoutProtection < Brakeman::BaseCheck
54
52
  :warning_code => :mass_assign_without_protection,
55
53
  :message => "Unprotected mass assignment",
56
54
  :code => call,
57
- :user_input => user_input,
55
+ :user_input => input,
58
56
  :confidence => confidence
59
57
 
60
58
  end
@@ -79,6 +79,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
79
79
 
80
80
  #Process a method call.
81
81
  def process_call exp
82
+ return exp if process_call_defn? exp
82
83
  target_var = exp.target
83
84
  target_var &&= target_var.deep_clone
84
85
  exp = process_default exp
@@ -142,7 +143,16 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
142
143
  end
143
144
  when :/
144
145
  if number? target and number? first_arg
145
- exp = Sexp.new(:lit, target.value / first_arg.value)
146
+ if first_arg.value == 0 and not target.value.is_a? Float
147
+ if @tracker
148
+ location = [@current_class, @current_method, "line #{first_arg.line}"].compact.join(' ')
149
+ require 'brakeman/processors/output_processor'
150
+ code = Brakeman::OutputProcessor.new.format(exp)
151
+ @tracker.error Exception.new("Potential divide by zero: #{code} (#{location})")
152
+ end
153
+ else
154
+ exp = Sexp.new(:lit, target.value / first_arg.value)
155
+ end
146
156
  end
147
157
  when :[]
148
158
  if array? target
@@ -103,7 +103,10 @@ class Brakeman::BaseProcessor < Brakeman::SexpProcessor
103
103
  #Processes the inside of an interpolated String.
104
104
  def process_evstr exp
105
105
  exp = exp.dup
106
- exp[1] = process exp[1]
106
+ if exp[1]
107
+ exp[1] = process exp[1]
108
+ end
109
+
107
110
  exp
108
111
  end
109
112
 
@@ -109,6 +109,8 @@ class Brakeman::ControllerProcessor < Brakeman::BaseProcessor
109
109
 
110
110
  #Look for specific calls inside the controller
111
111
  def process_call exp
112
+ return exp if process_call_defn? exp
113
+
112
114
  target = exp.target
113
115
  if sexp? target
114
116
  target = process target
@@ -141,7 +141,7 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
141
141
  if string_interp? exp
142
142
  exp.map! do |e|
143
143
  if sexp? e
144
- if node_type? e, :evstr
144
+ if node_type? e, :evstr and e[1]
145
145
  e = e.value
146
146
  end
147
147
 
@@ -59,4 +59,17 @@ module Brakeman::ProcessorHelper
59
59
 
60
60
  exp
61
61
  end
62
+
63
+ # e.g. private defn
64
+ def process_call_defn? exp
65
+ if call? exp and exp.target.nil? and node_type? exp.first_arg, :defn, :defs and [:private, :public, :protected].include? exp.method
66
+ prev_visibility = @visibility
67
+ @visibility = exp.method
68
+ process exp.first_arg
69
+ @visibility = prev_visibility
70
+ exp
71
+ else
72
+ false
73
+ end
74
+ end
62
75
  end
@@ -108,4 +108,12 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
108
108
 
109
109
  exp
110
110
  end
111
+
112
+ def process_call exp
113
+ if process_call_defn? exp
114
+ exp
115
+ else
116
+ process_default exp
117
+ end
118
+ end
111
119
  end
@@ -94,6 +94,8 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
94
94
  #such as include, attr_accessible, private, etc.
95
95
  def process_call exp
96
96
  return exp unless @current_class
97
+ return exp if process_call_defn? exp
98
+
97
99
  target = exp.target
98
100
  if sexp? target
99
101
  target = process target
@@ -139,6 +139,16 @@ class Brakeman::Report::HTML < Brakeman::Report::Base
139
139
  "<table id='#{code_id}' class='context' style='display:none'>" <<
140
140
  "<caption>#{CGI.escapeHTML warning_file(warning) || ''}</caption>"
141
141
 
142
+ output << <<-HTML
143
+ <thead style='display:none'>
144
+ <tr>
145
+ <th>line number</th>
146
+ <th>line content</th>
147
+ </tr>
148
+ </thead>
149
+ <tbody>
150
+ HTML
151
+
142
152
  unless context.empty?
143
153
  if warning.line - 1 == 1 or warning.line + 1 == 1
144
154
  error = " near_error"
@@ -184,7 +194,7 @@ class Brakeman::Report::HTML < Brakeman::Report::Base
184
194
  end
185
195
  end
186
196
 
187
- output << "</table></div>"
197
+ output << "</tbody></table></div>"
188
198
  end
189
199
 
190
200
  #Escape warning message and highlight user input in HTML output
@@ -1,18 +1,22 @@
1
1
  <h2>Controllers</h2>
2
2
 
3
3
  <table>
4
- <tr>
5
- <th>Name</th>
6
- <th>Parent</th>
7
- <th>Includes</th>
8
- <th>Routes</th>
9
- </tr>
10
- <% controller_rows.each do |row| %>
11
- <tr>
12
- <td><%= row['Name'] %></td>
13
- <td><%= row['Parent'] %></td>
14
- <td><%= row['Includes'] %></td>
15
- <td><%= row['Routes'] %></td>
16
- </tr>
17
- <% end %>
4
+ <thead>
5
+ <tr>
6
+ <th>Name</th>
7
+ <th>Parent</th>
8
+ <th>Includes</th>
9
+ <th>Routes</th>
10
+ </tr>
11
+ </thead>
12
+ <tbody>
13
+ <% controller_rows.each do |row| %>
14
+ <tr>
15
+ <td><%= row['Name'] %></td>
16
+ <td><%= row['Parent'] %></td>
17
+ <td><%= row['Includes'] %></td>
18
+ <td><%= row['Routes'] %></td>
19
+ </tr>
20
+ <% end %>
21
+ </tbody>
18
22
  </table>
@@ -1,17 +1,21 @@
1
1
  <p>Controller Warnings</p>
2
2
  <table>
3
- <tr>
4
- <th>Confidence</th>
5
- <th>Controller</th>
6
- <th>Warning Type</th>
7
- <th>Message</th>
8
- </tr>
9
- <% warnings.each do |warning| %>
10
- <tr>
11
- <td><%= warning['Confidence']%></td>
12
- <td><%= warning['Controller']%></td>
13
- <td><%= warning['Warning Type']%></td>
14
- <td><%= warning['Message']%></td>
15
- </tr>
16
- <% end %>
3
+ <thead>
4
+ <tr>
5
+ <th>Confidence</th>
6
+ <th>Controller</th>
7
+ <th>Warning Type</th>
8
+ <th>Message</th>
9
+ </tr>
10
+ </thead>
11
+ <tbody>
12
+ <% warnings.each do |warning| %>
13
+ <tr>
14
+ <td><%= warning['Confidence']%></td>
15
+ <td><%= warning['Controller']%></td>
16
+ <td><%= warning['Warning Type']%></td>
17
+ <td><%= warning['Message']%></td>
18
+ </tr>
19
+ <% end %>
20
+ </tbody>
17
21
  </table>
@@ -2,10 +2,13 @@
2
2
  <div>
3
3
  <div id='errors_table' style='display:none'>
4
4
  <table>
5
- <tr>
6
- <th>Error</th>
7
- <th>Location</th>
8
- </tr>
5
+ <thead>
6
+ <tr>
7
+ <th>Error</th>
8
+ <th>Location</th>
9
+ </tr>
10
+ </thead>
11
+ <tbody>
9
12
  <% tracker.errors.each do |warning| %>
10
13
  <tr>
11
14
  <td><%= CGI.escapeHTML warning[:error] %></td>
@@ -20,6 +23,7 @@
20
23
  </td>
21
24
  </tr>
22
25
  <% end %>
26
+ </tbody>
23
27
  </table>
24
28
  </div>
25
29
  </div>
@@ -3,7 +3,9 @@
3
3
  <head>
4
4
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
5
  <title>Brakeman Report</title>
6
- <script>
6
+ <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
7
+ <script type="text/javascript" src="https://cdn.datatables.net/1.10.9/js/jquery.dataTables.min.js"></script>
8
+ <script type="text/javascript">
7
9
  function toggle(context) {
8
10
  var elem = document.getElementById(context);
9
11
 
@@ -14,6 +16,14 @@
14
16
 
15
17
  elem.parentNode.scrollIntoView();
16
18
  }
19
+
20
+ $(document).ready(function() {
21
+ $('table').DataTable({
22
+ searching: false,
23
+ paging: false,
24
+ info: false
25
+ });
26
+ });
17
27
  </script>
18
28
  <style>
19
29
  <%= css %>
@@ -23,22 +33,26 @@
23
33
 
24
34
  <h1>Brakeman Report</h1>
25
35
  <table>
26
- <tr>
27
- <th>Application Path</th>
28
- <th>Rails Version</th>
29
- <th>Brakeman Version</th>
30
- <th>Report Time</th>
31
- <th>Checks Performed</th>
32
- </tr>
33
- <tr>
34
- <td><%= tracker.app_path %></td>
35
- <td><%= rails_version %></td>
36
- <td><%= brakeman_version %>
37
- <td>
38
- <%= tracker.start_time %><br><br>
39
- <%= tracker.duration %> seconds
40
- </td>
41
- <td><%= checks.checks_run.sort.join(", ") %></td>
42
- </tr>
36
+ <thead>
37
+ <tr>
38
+ <th>Application Path</th>
39
+ <th>Rails Version</th>
40
+ <th>Brakeman Version</th>
41
+ <th>Report Time</th>
42
+ <th>Checks Performed</th>
43
+ </tr>
44
+ </thead>
45
+ <tbody>
46
+ <tr>
47
+ <td><%= tracker.app_path %></td>
48
+ <td><%= rails_version %></td>
49
+ <td><%= brakeman_version %>
50
+ <td>
51
+ <%= tracker.start_time %><br><br>
52
+ <%= tracker.duration %> seconds
53
+ </td>
54
+ <td><%= checks.checks_run.sort.join(", ") %></td>
55
+ </tr>
56
+ </tbody>
43
57
  </table>
44
58
  <br>
@@ -1,13 +1,16 @@
1
1
  <div onClick="toggle('ignored_table');"> <h2><%= warnings.length %> Ignored Warnings (click to see them)</h2 ></div>
2
2
  <div>
3
3
  <table style="display:none" id="ignored_table">
4
- <tr>
5
- <th>Confidence</th>
6
- <th>File</th>
7
- <th>Warning Type</th>
8
- <th>Message</th>
9
- <th>Note</th>
10
- </tr>
4
+ <thead>
5
+ <tr>
6
+ <th>Confidence</th>
7
+ <th>File</th>
8
+ <th>Warning Type</th>
9
+ <th>Message</th>
10
+ <th>Note</th>
11
+ </tr>
12
+ </thead>
13
+ <tbody>
11
14
  <% warnings.each do |warning| %>
12
15
  <tr>
13
16
  <td><%= warning['Confidence']%></td>
@@ -17,5 +20,6 @@
17
20
  <td><%= warning['Note']%></td>
18
21
  </tr>
19
22
  <% end %>
23
+ </tbody>
20
24
  </table>
21
25
  </div>
@@ -1,17 +1,21 @@
1
1
  <p>Model Warnings</p>
2
2
  <table>
3
- <tr>
4
- <th>Confidence</th>
5
- <th>Model</th>
6
- <th>Warning Type</th>
7
- <th>Message</th>
8
- </tr>
9
- <% warnings.each do |warning| %>
10
- <tr>
11
- <td><%= warning['Confidence']%></td>
12
- <td><%= warning['Model']%></td>
13
- <td><%= warning['Warning Type']%></td>
14
- <td><%= warning['Message']%></td>
15
- </tr>
16
- <% end %>
3
+ <thead>
4
+ <tr>
5
+ <th>Confidence</th>
6
+ <th>Model</th>
7
+ <th>Warning Type</th>
8
+ <th>Message</th>
9
+ </tr>
10
+ </thead>
11
+ <tbody>
12
+ <% warnings.each do |warning| %>
13
+ <tr>
14
+ <td><%= warning['Confidence']%></td>
15
+ <td><%= warning['Model']%></td>
16
+ <td><%= warning['Warning Type']%></td>
17
+ <td><%= warning['Message']%></td>
18
+ </tr>
19
+ <% end %>
20
+ </tbody>
17
21
  </table>