brakeman 3.1.1 → 3.1.2

Sign up to get free protection for your applications and to get access to all the features.
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>