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.
- checksums.yaml +4 -4
- data/CHANGES +18 -0
- data/lib/brakeman.rb +17 -13
- data/lib/brakeman/checks/base_check.rb +2 -0
- data/lib/brakeman/checks/check_content_tag.rb +2 -2
- data/lib/brakeman/checks/check_cross_site_scripting.rb +6 -6
- data/lib/brakeman/checks/check_deserialize.rb +1 -1
- data/lib/brakeman/checks/check_evaluation.rb +1 -1
- data/lib/brakeman/checks/check_execute.rb +3 -5
- data/lib/brakeman/checks/check_file_access.rb +1 -1
- data/lib/brakeman/checks/check_forgery_setting.rb +2 -1
- data/lib/brakeman/checks/check_link_to.rb +2 -2
- data/lib/brakeman/checks/check_link_to_href.rb +10 -3
- data/lib/brakeman/checks/check_mass_assignment.rb +2 -4
- data/lib/brakeman/checks/check_model_attributes.rb +1 -0
- data/lib/brakeman/checks/check_model_serialize.rb +2 -1
- data/lib/brakeman/checks/check_number_to_currency.rb +0 -1
- data/lib/brakeman/checks/check_redirect.rb +1 -1
- data/lib/brakeman/checks/check_regex_dos.rb +1 -1
- data/lib/brakeman/checks/check_render.rb +1 -1
- data/lib/brakeman/checks/check_render_inline.rb +28 -16
- data/lib/brakeman/checks/check_select_tag.rb +1 -1
- data/lib/brakeman/checks/check_send.rb +1 -1
- data/lib/brakeman/checks/check_session_manipulation.rb +1 -1
- data/lib/brakeman/checks/check_simple_format.rb +1 -1
- data/lib/brakeman/checks/check_sql.rb +2 -2
- data/lib/brakeman/checks/check_symbol_dos.rb +1 -1
- data/lib/brakeman/checks/check_unsafe_reflection.rb +1 -1
- data/lib/brakeman/checks/check_unscoped_find.rb +1 -1
- data/lib/brakeman/checks/check_weak_hash.rb +0 -1
- data/lib/brakeman/checks/check_without_protection.rb +1 -3
- data/lib/brakeman/processors/alias_processor.rb +11 -1
- data/lib/brakeman/processors/base_processor.rb +4 -1
- data/lib/brakeman/processors/controller_processor.rb +2 -0
- data/lib/brakeman/processors/haml_template_processor.rb +1 -1
- data/lib/brakeman/processors/lib/processor_helper.rb +13 -0
- data/lib/brakeman/processors/library_processor.rb +8 -0
- data/lib/brakeman/processors/model_processor.rb +2 -0
- data/lib/brakeman/report/report_html.rb +11 -1
- data/lib/brakeman/report/templates/controller_overview.html.erb +18 -14
- data/lib/brakeman/report/templates/controller_warnings.html.erb +18 -14
- data/lib/brakeman/report/templates/error_overview.html.erb +8 -4
- data/lib/brakeman/report/templates/header.html.erb +32 -18
- data/lib/brakeman/report/templates/ignored_warnings.html.erb +11 -7
- data/lib/brakeman/report/templates/model_warnings.html.erb +18 -14
- data/lib/brakeman/report/templates/overview.html.erb +32 -28
- data/lib/brakeman/report/templates/security_warnings.html.erb +18 -14
- data/lib/brakeman/report/templates/template_overview.html.erb +10 -6
- data/lib/brakeman/report/templates/view_warnings.html.erb +30 -26
- data/lib/brakeman/report/templates/warning_overview.html.erb +12 -8
- data/lib/brakeman/tracker/collection.rb +12 -0
- data/lib/brakeman/tracker/controller.rb +2 -2
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning.rb +29 -6
- data/lib/ruby_parser/bm_sexp.rb +18 -0
- 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
|
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
|
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?
|
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
|
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
|
47
|
+
:user_input => input,
|
48
48
|
:confidence => confidence
|
49
49
|
end
|
50
50
|
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 =>
|
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
|
-
|
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
|
-
|
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
|
@@ -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
|
@@ -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
|
-
<
|
5
|
-
<
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
<
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
<
|
4
|
-
<
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
<
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
<
|
6
|
-
<
|
7
|
-
|
8
|
-
|
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
|
-
<
|
27
|
-
<
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
<
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
-
<
|
5
|
-
<
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
<
|
4
|
-
<
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
<
|
14
|
-
|
15
|
-
|
16
|
-
|
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>
|