brakeman-lib 3.3.3 → 3.3.4
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 +7 -0
- data/lib/brakeman/app_tree.rb +18 -20
- data/lib/brakeman/checks/check_content_tag.rb +44 -4
- data/lib/brakeman/checks/check_forgery_setting.rb +26 -33
- data/lib/brakeman/checks/check_sql_cves.rb +5 -0
- data/lib/brakeman/checks/check_symbol_dos.rb +1 -1
- data/lib/brakeman/processors/alias_processor.rb +1 -12
- data/lib/brakeman/processors/base_processor.rb +1 -12
- data/lib/brakeman/processors/lib/processor_helper.rb +13 -0
- data/lib/brakeman/processors/library_processor.rb +1 -13
- data/lib/brakeman/processors/output_processor.rb +8 -40
- data/lib/brakeman/report/report_markdown.rb +17 -66
- data/lib/brakeman/report/report_table.rb +18 -46
- data/lib/brakeman/tracker/controller.rb +13 -13
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning_codes.rb +2 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0cded9ea0fa47da3c2d8aba50ad44df95d2e5897
|
4
|
+
data.tar.gz: fd8d169620308f1ebcdbd5f71b48501ee4c1ad16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 37ef8199c02c832379953e235c98bb82dbf1f898943152e90e952a85e2b4cc6e8c4e47cf5e6404c7e0977d0ac17f5487c63df8dc34009694612ff0691b432bf1
|
7
|
+
data.tar.gz: c6a42b593a626441072b440f7bb99f60727d18213b38fb0134a828e8fa82da5e4dc9106b43e482a0c686c0269a4459f567884c20cfa974bff7983b6d99eceb84
|
data/CHANGES
CHANGED
data/lib/brakeman/app_tree.rb
CHANGED
@@ -53,6 +53,7 @@ module Brakeman
|
|
53
53
|
|
54
54
|
def initialize(root, init_options = {})
|
55
55
|
@root = root
|
56
|
+
@project_root_path = Pathname.new(@root)
|
56
57
|
@skip_files = init_options[:skip_files]
|
57
58
|
@only_files = init_options[:only_files]
|
58
59
|
@additional_libs_path = init_options[:additional_libs_path] || []
|
@@ -133,34 +134,31 @@ module Brakeman
|
|
133
134
|
|
134
135
|
def select_only_files(paths)
|
135
136
|
return paths unless @only_files
|
136
|
-
|
137
|
+
|
137
138
|
paths.select do |path|
|
138
|
-
|
139
|
-
# relative root never has a leading separator. But, we use a leading
|
140
|
-
# separator in a @skip_files entry to imply that a directory is
|
141
|
-
# "absolute" with respect to the project directory.
|
142
|
-
project_relative_path = File.join(
|
143
|
-
File::SEPARATOR,
|
144
|
-
absolute_path.relative_path_from(project_root).to_s
|
145
|
-
)
|
146
|
-
@only_files.match(project_relative_path)
|
139
|
+
match_path @only_files, path
|
147
140
|
end
|
148
141
|
end
|
149
142
|
|
150
143
|
def reject_skipped_files(paths)
|
151
144
|
return paths unless @skip_files
|
152
|
-
|
145
|
+
|
153
146
|
paths.reject do |path|
|
154
|
-
|
155
|
-
# relative root never has a leading separator. But, we use a leading
|
156
|
-
# separator in a @skip_files entry to imply that a directory is
|
157
|
-
# "absolute" with respect to the project directory.
|
158
|
-
project_relative_path = File.join(
|
159
|
-
File::SEPARATOR,
|
160
|
-
absolute_path.relative_path_from(project_root).to_s
|
161
|
-
)
|
162
|
-
@skip_files.match(project_relative_path)
|
147
|
+
match_path @skip_files, path
|
163
148
|
end
|
164
149
|
end
|
150
|
+
|
151
|
+
def match_path files, path
|
152
|
+
absolute_path = Pathname.new(path)
|
153
|
+
# relative root never has a leading separator. But, we use a leading
|
154
|
+
# separator in a @skip_files entry to imply that a directory is
|
155
|
+
# "absolute" with respect to the project directory.
|
156
|
+
project_relative_path = File.join(
|
157
|
+
File::SEPARATOR,
|
158
|
+
absolute_path.relative_path_from(@project_root_path).to_s
|
159
|
+
)
|
160
|
+
|
161
|
+
files.match(project_relative_path)
|
162
|
+
end
|
165
163
|
end
|
166
164
|
end
|
@@ -28,16 +28,18 @@ class Brakeman::CheckContentTag < Brakeman::CheckCrossSiteScripting
|
|
28
28
|
:will_paginate].merge tracker.options[:safe_methods]
|
29
29
|
|
30
30
|
@known_dangerous = []
|
31
|
-
|
31
|
+
@content_tags = tracker.find_call :target => false, :method => :content_tag
|
32
32
|
|
33
33
|
@models = tracker.models.keys
|
34
34
|
@inspect_arguments = tracker.options[:check_arguments]
|
35
35
|
@mark = nil
|
36
36
|
|
37
37
|
Brakeman.debug "Checking for XSS in content_tag"
|
38
|
-
|
38
|
+
@content_tags.each do |call|
|
39
39
|
process_result call
|
40
40
|
end
|
41
|
+
|
42
|
+
check_cve_2016_6316
|
41
43
|
end
|
42
44
|
|
43
45
|
def process_result result
|
@@ -73,7 +75,7 @@ class Brakeman::CheckContentTag < Brakeman::CheckCrossSiteScripting
|
|
73
75
|
#By default, content_tag escapes attribute values passed in as a hash.
|
74
76
|
#But this behavior can be disabled. So only check attributes hash
|
75
77
|
#if they are explicitly not escaped.
|
76
|
-
if not @matched and attributes and false? escape_attr
|
78
|
+
if not @matched and attributes and (false? escape_attr or cve_2016_6316?)
|
77
79
|
if request_value? attributes or not hash? attributes
|
78
80
|
check_argument result, attributes
|
79
81
|
else #check hash values
|
@@ -87,7 +89,7 @@ class Brakeman::CheckContentTag < Brakeman::CheckCrossSiteScripting
|
|
87
89
|
|
88
90
|
def check_argument result, exp
|
89
91
|
#Check contents of raw() calls directly
|
90
|
-
if
|
92
|
+
if raw? exp
|
91
93
|
arg = process exp.first_arg
|
92
94
|
else
|
93
95
|
arg = process exp
|
@@ -154,7 +156,45 @@ class Brakeman::CheckContentTag < Brakeman::CheckCrossSiteScripting
|
|
154
156
|
exp
|
155
157
|
end
|
156
158
|
|
159
|
+
def check_cve_2016_6316
|
160
|
+
if cve_2016_6316?
|
161
|
+
confidence = if @content_tags.any?
|
162
|
+
CONFIDENCE[:high]
|
163
|
+
else
|
164
|
+
CONFIDENCE[:med]
|
165
|
+
end
|
166
|
+
|
167
|
+
fix_version = case
|
168
|
+
when version_between?("3.0.0", "3.2.22.3")
|
169
|
+
"3.2.22.4"
|
170
|
+
when version_between?("4.0.0", "4.2.7.0")
|
171
|
+
"4.2.7.1"
|
172
|
+
when version_between?("5.0.0", "5.0.0")
|
173
|
+
"5.0.0"
|
174
|
+
when (version.nil? and tracker.options[:rails3])
|
175
|
+
"3.2.22.4"
|
176
|
+
when (version.nil? and tracker.options[:rails4])
|
177
|
+
"4.2.7.2"
|
178
|
+
else
|
179
|
+
return
|
180
|
+
end
|
181
|
+
|
182
|
+
warn :warning_type => "Cross Site Scripting",
|
183
|
+
:warning_code => :CVE_2016_6316,
|
184
|
+
:message => "Rails #{rails_version} content_tag does not escape double quotes in attribute values (CVE-2016-6316). Upgrade to #{fix_version}",
|
185
|
+
:confidence => confidence,
|
186
|
+
:gem_info => gemfile_or_environment,
|
187
|
+
:link_path => "https://groups.google.com/d/msg/ruby-security-ann/8B2iV2tPRSE/JkjCJkSoCgAJ"
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
157
191
|
def raw? exp
|
158
192
|
call? exp and exp.method == :raw
|
159
193
|
end
|
194
|
+
|
195
|
+
def cve_2016_6316?
|
196
|
+
version_between? "3.0.0", "3.2.22.3" or
|
197
|
+
version_between? "4.0.0", "4.2.7.0" or
|
198
|
+
version_between? "5.0.0", "5.0.0.0"
|
199
|
+
end
|
160
200
|
end
|
@@ -14,61 +14,54 @@ class Brakeman::CheckForgerySetting < Brakeman::BaseCheck
|
|
14
14
|
return unless app_controller and app_controller.ancestor? :"ActionController::Base"
|
15
15
|
|
16
16
|
if tracker.config.allow_forgery_protection?
|
17
|
-
|
18
|
-
:
|
19
|
-
:warning_code => :csrf_protection_disabled,
|
20
|
-
:message => "Forgery protection is disabled",
|
21
|
-
:confidence => CONFIDENCE[:high],
|
22
|
-
:file => app_controller.file
|
17
|
+
csrf_warning :warning_code => :csrf_protection_disabled,
|
18
|
+
:message => "Forgery protection is disabled"
|
23
19
|
|
24
20
|
elsif app_controller and not app_controller.protect_from_forgery?
|
25
|
-
|
26
|
-
warn :controller => :ApplicationController,
|
27
|
-
:warning_type => "Cross-Site Request Forgery",
|
28
|
-
:warning_code => :csrf_protection_missing,
|
21
|
+
csrf_warning :warning_code => :csrf_protection_missing,
|
29
22
|
:message => "'protect_from_forgery' should be called in ApplicationController",
|
30
|
-
:confidence => CONFIDENCE[:high],
|
31
|
-
:file => app_controller.file,
|
32
23
|
:line => app_controller.top_line
|
33
24
|
|
34
25
|
elsif version_between? "2.1.0", "2.3.10"
|
35
|
-
|
36
|
-
warn :controller => :ApplicationController,
|
37
|
-
:warning_type => "Cross-Site Request Forgery",
|
38
|
-
:warning_code => :CVE_2011_0447,
|
39
|
-
:message => "CSRF protection is flawed in unpatched versions of Rails #{rails_version} (CVE-2011-0447). Upgrade to 2.3.11 or apply patches as needed",
|
40
|
-
:confidence => CONFIDENCE[:high],
|
41
|
-
:gem_info => gemfile_or_environment,
|
42
|
-
:link_path => "https://groups.google.com/d/topic/rubyonrails-security/LZWjzCPgNmU/discussion"
|
26
|
+
cve_2011_0447 "2.3.11"
|
43
27
|
|
44
28
|
elsif version_between? "3.0.0", "3.0.3"
|
29
|
+
cve_2011_0447 "3.0.4"
|
45
30
|
|
46
|
-
warn :controller => :ApplicationController,
|
47
|
-
:warning_type => "Cross-Site Request Forgery",
|
48
|
-
:warning_code => :CVE_2011_0447,
|
49
|
-
:message => "CSRF protection is flawed in unpatched versions of Rails #{rails_version} (CVE-2011-0447). Upgrade to 3.0.4 or apply patches as needed",
|
50
|
-
:confidence => CONFIDENCE[:high],
|
51
|
-
:gem_info => gemfile_or_environment,
|
52
|
-
:link_path => "https://groups.google.com/d/topic/rubyonrails-security/LZWjzCPgNmU/discussion"
|
53
31
|
elsif version_between? "4.0.0", "100.0.0" and forgery_opts = app_controller.options[:protect_from_forgery]
|
54
|
-
|
55
32
|
unless forgery_opts.is_a?(Array) and sexp?(forgery_opts.first) and
|
56
33
|
access_arg = hash_access(forgery_opts.first.first_arg, :with) and symbol? access_arg and
|
57
34
|
access_arg.value == :exception
|
58
35
|
|
59
36
|
args = {
|
60
|
-
:controller => :ApplicationController,
|
61
|
-
:warning_type => "Cross-Site Request Forgery",
|
62
37
|
:warning_code => :csrf_not_protected_by_raising_exception,
|
63
38
|
:message => "protect_from_forgery should be configured with 'with: :exception'",
|
64
|
-
:confidence => CONFIDENCE[:med]
|
65
|
-
:file => app_controller.file
|
39
|
+
:confidence => CONFIDENCE[:med]
|
66
40
|
}
|
67
41
|
|
68
42
|
args.merge!(:code => forgery_opts.first) if forgery_opts.is_a?(Array)
|
69
43
|
|
70
|
-
|
44
|
+
csrf_warning args
|
71
45
|
end
|
72
46
|
end
|
73
47
|
end
|
48
|
+
|
49
|
+
def csrf_warning opts
|
50
|
+
opts = {
|
51
|
+
:controller => :ApplicationController,
|
52
|
+
:warning_type => "Cross-Site Request Forgery",
|
53
|
+
:confidence => CONFIDENCE[:high],
|
54
|
+
:file => tracker.controllers[:ApplicationController].file
|
55
|
+
}.merge opts
|
56
|
+
|
57
|
+
warn opts
|
58
|
+
end
|
59
|
+
|
60
|
+
def cve_2011_0447 new_version
|
61
|
+
csrf_warning :warning_code => :CVE_2011_0447,
|
62
|
+
:message => "CSRF protection is flawed in unpatched versions of Rails #{rails_version} (CVE-2011-0447). Upgrade to #{new_version} or apply patches as needed",
|
63
|
+
:gem_info => gemfile_or_environment,
|
64
|
+
:file => nil,
|
65
|
+
:link_path => "https://groups.google.com/d/topic/rubyonrails-security/LZWjzCPgNmU/discussion"
|
66
|
+
end
|
74
67
|
end
|
@@ -37,6 +37,11 @@ class Brakeman::CheckSQLCVEs < Brakeman::BaseCheck
|
|
37
37
|
:versions => [%w[2.0.0 2.3.15 2.3.16], %w[3.0.0 3.0.18 3.0.19], %w[3.1.0 3.1.9 3.1.10], %w[3.2.0 3.2.10 3.2.11]],
|
38
38
|
:url => "https://groups.google.com/d/topic/rubyonrails-security/c7jT-EeN9eI/discussion"
|
39
39
|
},
|
40
|
+
{
|
41
|
+
:cve => "CVE-2016-6317",
|
42
|
+
:versions => [%w[4.2.0 4.2.7.0 4.2.7.1]],
|
43
|
+
:url => "https://groups.google.com/d/msg/ruby-security-ann/WccgKSKiPZA/9DrsDVSoCgAJ"
|
44
|
+
},
|
40
45
|
|
41
46
|
]
|
42
47
|
|
@@ -8,7 +8,7 @@ class Brakeman::CheckSymbolDoS < Brakeman::BaseCheck
|
|
8
8
|
@description = "Checks for symbol denial of service"
|
9
9
|
|
10
10
|
def run_check
|
11
|
-
return if rails_version and rails_version
|
11
|
+
return if rails_version and rails_version >= "5.0.0"
|
12
12
|
|
13
13
|
tracker.find_call(:methods => UNSAFE_METHODS, :nested => true).each do |result|
|
14
14
|
check_unsafe_symbol_creation(result)
|
@@ -522,18 +522,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
|
|
522
522
|
exp.rhs = process exp.rhs
|
523
523
|
end
|
524
524
|
|
525
|
-
file
|
526
|
-
when @file_name
|
527
|
-
@file_name
|
528
|
-
when @current_class.is_a?(Brakeman::Collection)
|
529
|
-
@current_class.file
|
530
|
-
when @current_module.is_a?(Brakeman::Collection)
|
531
|
-
@current_module.file
|
532
|
-
else
|
533
|
-
nil
|
534
|
-
end
|
535
|
-
|
536
|
-
@tracker.add_constant exp.lhs, exp.rhs, :file => file if @tracker
|
525
|
+
@tracker.add_constant exp.lhs, exp.rhs, :file => current_file_name if @tracker
|
537
526
|
|
538
527
|
if exp.lhs.is_a? Symbol
|
539
528
|
match = Sexp.new(:const, exp.lhs)
|
@@ -183,18 +183,7 @@ class Brakeman::BaseProcessor < Brakeman::SexpProcessor
|
|
183
183
|
end
|
184
184
|
|
185
185
|
def process_cdecl exp
|
186
|
-
file
|
187
|
-
when @file_name
|
188
|
-
@file_name
|
189
|
-
when @current_class.is_a?(Brakeman::Collection)
|
190
|
-
@current_class.file
|
191
|
-
when @current_module.is_a?(Brakeman::Collection)
|
192
|
-
@current_module.file
|
193
|
-
else
|
194
|
-
nil
|
195
|
-
end
|
196
|
-
|
197
|
-
@tracker.add_constant exp.lhs, exp.rhs, :file => file if @tracker
|
186
|
+
@tracker.add_constant exp.lhs, exp.rhs, :file => current_file_name if @tracker
|
198
187
|
exp
|
199
188
|
end
|
200
189
|
|
@@ -72,4 +72,17 @@ module Brakeman::ProcessorHelper
|
|
72
72
|
false
|
73
73
|
end
|
74
74
|
end
|
75
|
+
|
76
|
+
def current_file_name
|
77
|
+
case
|
78
|
+
when @file_name
|
79
|
+
@file_name
|
80
|
+
when @current_class.is_a?(Brakeman::Collection)
|
81
|
+
@current_class.file
|
82
|
+
when @current_module.is_a?(Brakeman::Collection)
|
83
|
+
@current_module.file
|
84
|
+
else
|
85
|
+
nil
|
86
|
+
end
|
87
|
+
end
|
75
88
|
end
|
@@ -42,19 +42,7 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
|
|
42
42
|
exp
|
43
43
|
end
|
44
44
|
|
45
|
-
|
46
|
-
exp = @alias_processor.process exp
|
47
|
-
|
48
|
-
if @current_class
|
49
|
-
exp.body = process_all! exp.body
|
50
|
-
@current_class.add_method :public, exp.method_name, exp, @file_name
|
51
|
-
elsif @current_module
|
52
|
-
exp.body = process_all! exp.body
|
53
|
-
@current_module.add_method :public, exp.method_name, exp, @file_name
|
54
|
-
end
|
55
|
-
|
56
|
-
exp
|
57
|
-
end
|
45
|
+
alias process_defs process_defn
|
58
46
|
|
59
47
|
def process_call exp
|
60
48
|
if process_call_defn? exp
|
@@ -86,55 +86,23 @@ class Brakeman::OutputProcessor < Ruby2Ruby
|
|
86
86
|
end
|
87
87
|
|
88
88
|
def process_output exp
|
89
|
-
|
90
|
-
""
|
91
|
-
else
|
92
|
-
res = process exp[0]
|
93
|
-
|
94
|
-
if res == ""
|
95
|
-
""
|
96
|
-
else
|
97
|
-
"[Output] #{res}"
|
98
|
-
end
|
99
|
-
end
|
100
|
-
exp.clear
|
101
|
-
out
|
89
|
+
output_format exp, "Output"
|
102
90
|
end
|
103
91
|
|
104
92
|
def process_escaped_output exp
|
105
|
-
|
106
|
-
""
|
107
|
-
else
|
108
|
-
res = process exp[0]
|
109
|
-
|
110
|
-
if res == ""
|
111
|
-
""
|
112
|
-
else
|
113
|
-
"[Escaped Output] #{res}"
|
114
|
-
end
|
115
|
-
end
|
116
|
-
exp.clear
|
117
|
-
out
|
93
|
+
output_format exp, "Escaped Output"
|
118
94
|
end
|
119
95
|
|
120
96
|
|
121
97
|
def process_format exp
|
122
|
-
|
123
|
-
""
|
124
|
-
else
|
125
|
-
res = process exp[0]
|
126
|
-
|
127
|
-
if res == ""
|
128
|
-
""
|
129
|
-
else
|
130
|
-
"[Format] #{res}"
|
131
|
-
end
|
132
|
-
end
|
133
|
-
exp.clear
|
134
|
-
out
|
98
|
+
output_format exp, "Format"
|
135
99
|
end
|
136
100
|
|
137
101
|
def process_format_escaped exp
|
102
|
+
output_format exp, "Escaped"
|
103
|
+
end
|
104
|
+
|
105
|
+
def output_format exp, tag
|
138
106
|
out = if exp[0].node_type == :str or exp[0].node_type == :ignore
|
139
107
|
""
|
140
108
|
else
|
@@ -143,7 +111,7 @@ class Brakeman::OutputProcessor < Ruby2Ruby
|
|
143
111
|
if res == ""
|
144
112
|
""
|
145
113
|
else
|
146
|
-
"[
|
114
|
+
"[#{tag}] #{res}"
|
147
115
|
end
|
148
116
|
end
|
149
117
|
exp.clear
|
@@ -1,6 +1,6 @@
|
|
1
|
-
|
1
|
+
require 'brakeman/report/report_table'
|
2
2
|
|
3
|
-
class Brakeman::Report::Markdown < Brakeman::Report::
|
3
|
+
class Brakeman::Report::Markdown < Brakeman::Report::Table
|
4
4
|
|
5
5
|
class MarkdownTable < Terminal::Table
|
6
6
|
|
@@ -21,6 +21,11 @@ class Brakeman::Report::Markdown < Brakeman::Report::Base
|
|
21
21
|
|
22
22
|
end
|
23
23
|
|
24
|
+
def initialize *args
|
25
|
+
super
|
26
|
+
@table = MarkdownTable
|
27
|
+
end
|
28
|
+
|
24
29
|
def generate_report
|
25
30
|
out = "# BRAKEMAN REPORT\n\n" <<
|
26
31
|
generate_metadata.to_s << "\n\n" <<
|
@@ -42,22 +47,19 @@ class Brakeman::Report::Markdown < Brakeman::Report::Base
|
|
42
47
|
generate_templates.to_s << "\n\n"
|
43
48
|
end
|
44
49
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
+
output_table("Errors", generate_errors, out)
|
51
|
+
output_table("SECURITY WARNINGS", generate_warnings, out)
|
52
|
+
output_table("Controller Warnings:", generate_controller_warnings, out)
|
53
|
+
output_table("Model Warnings:", generate_model_warnings, out)
|
54
|
+
output_table("View Warnings:", generate_template_warnings, out)
|
50
55
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
res = generate_model_warnings
|
55
|
-
out << "### Model Warnings:\n\n" << res.to_s << "\n\n" if res
|
56
|
+
out
|
57
|
+
end
|
56
58
|
|
57
|
-
|
58
|
-
|
59
|
+
def output_table title, result, output
|
60
|
+
return unless result
|
59
61
|
|
60
|
-
|
62
|
+
output << "### #{title}\n\n#{result.to_s}\n\n"
|
61
63
|
end
|
62
64
|
|
63
65
|
def generate_metadata
|
@@ -81,57 +83,6 @@ class Brakeman::Report::Markdown < Brakeman::Report::Base
|
|
81
83
|
end
|
82
84
|
end
|
83
85
|
|
84
|
-
def generate_overview
|
85
|
-
num_warnings = all_warnings.length
|
86
|
-
|
87
|
-
MarkdownTable.new(:headings => ['Scanned/Reported', 'Total']) do |t|
|
88
|
-
t.add_row ['Controllers', tracker.controllers.length]
|
89
|
-
t.add_row ['Models', tracker.models.length - 1]
|
90
|
-
t.add_row ['Templates', number_of_templates(@tracker)]
|
91
|
-
t.add_row ['Errors', tracker.errors.length]
|
92
|
-
t.add_row ['Security Warnings', "#{num_warnings} (#{warnings_summary[:high_confidence]})"]
|
93
|
-
t.add_row ['Ignored Warnings', ignored_warnings.length] unless ignored_warnings.empty?
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
#Generate listings of templates and their output
|
98
|
-
def generate_templates
|
99
|
-
out_processor = Brakeman::OutputProcessor.new
|
100
|
-
template_rows = {}
|
101
|
-
tracker.templates.each do |name, template|
|
102
|
-
template.each_output do |out|
|
103
|
-
out = out_processor.format out
|
104
|
-
template_rows[name] ||= []
|
105
|
-
template_rows[name] << out.gsub("\n", ";").gsub(/\s+/, " ")
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
template_rows = template_rows.sort_by{|name, value| name.to_s}
|
110
|
-
|
111
|
-
output = ''
|
112
|
-
template_rows.each do |template|
|
113
|
-
output << template.first.to_s << "\n\n"
|
114
|
-
table = MarkdownTable.new(:headings => ['Output']) do |t|
|
115
|
-
# template[1] is an array of calls
|
116
|
-
template[1].each do |v|
|
117
|
-
t.add_row [v]
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
output << table.to_s << "\n\n"
|
122
|
-
end
|
123
|
-
|
124
|
-
output
|
125
|
-
end
|
126
|
-
|
127
|
-
def render_array template, headings, value_array, locals
|
128
|
-
return if value_array.empty?
|
129
|
-
|
130
|
-
MarkdownTable.new(:headings => headings) do |t|
|
131
|
-
value_array.each { |value_row| t.add_row value_row }
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
86
|
def convert_warning warning, original
|
136
87
|
warning["Confidence"] = TEXT_CONFIDENCE[warning["Confidence"]]
|
137
88
|
warning["Message"] = markdown_message original, warning["Message"]
|
@@ -1,6 +1,11 @@
|
|
1
1
|
Brakeman.load_brakeman_dependency 'terminal-table'
|
2
2
|
|
3
3
|
class Brakeman::Report::Table < Brakeman::Report::Base
|
4
|
+
def initialize *args
|
5
|
+
super
|
6
|
+
@table = Terminal::Table
|
7
|
+
end
|
8
|
+
|
4
9
|
def generate_report
|
5
10
|
out = text_header <<
|
6
11
|
"\n\n+SUMMARY+\n\n" <<
|
@@ -20,29 +25,26 @@ class Brakeman::Report::Table < Brakeman::Report::Base
|
|
20
25
|
truncate_table(generate_templates.to_s) << "\n"
|
21
26
|
end
|
22
27
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
res = generate_controller_warnings
|
30
|
-
out << "\n\n\nController Warnings:\n\n" << truncate_table(res.to_s) if res
|
31
|
-
|
32
|
-
res = generate_model_warnings
|
33
|
-
out << "\n\n\nModel Warnings:\n\n" << truncate_table(res.to_s) if res
|
34
|
-
|
35
|
-
res = generate_template_warnings
|
36
|
-
out << "\n\nView Warnings:\n\n" << truncate_table(res.to_s) if res
|
28
|
+
output_table("+Errors+", generate_errors, out)
|
29
|
+
output_table("+SECURITY WARNINGS+", generate_warnings, out)
|
30
|
+
output_table("Controller Warnings:", generate_controller_warnings, out)
|
31
|
+
output_table("Model Warnings:", generate_model_warnings, out)
|
32
|
+
output_table("View Warnings:", generate_template_warnings, out)
|
37
33
|
|
38
34
|
out << "\n"
|
39
35
|
out
|
40
36
|
end
|
41
37
|
|
38
|
+
def output_table title, result, output
|
39
|
+
return unless result
|
40
|
+
|
41
|
+
output << "\n\n#{title}\n\n#{truncate_table(result.to_s)}"
|
42
|
+
end
|
43
|
+
|
42
44
|
def generate_overview
|
43
45
|
num_warnings = all_warnings.length
|
44
46
|
|
45
|
-
|
47
|
+
@table.new(:headings => ['Scanned/Reported', 'Total']) do |t|
|
46
48
|
t.add_row ['Controllers', tracker.controllers.length]
|
47
49
|
t.add_row ['Models', tracker.models.length - 1]
|
48
50
|
t.add_row ['Templates', number_of_templates(@tracker)]
|
@@ -52,40 +54,10 @@ class Brakeman::Report::Table < Brakeman::Report::Base
|
|
52
54
|
end
|
53
55
|
end
|
54
56
|
|
55
|
-
#Generate listings of templates and their output
|
56
|
-
def generate_templates
|
57
|
-
out_processor = Brakeman::OutputProcessor.new
|
58
|
-
template_rows = {}
|
59
|
-
tracker.templates.each do |name, template|
|
60
|
-
template.each_output do |out|
|
61
|
-
out = out_processor.format out
|
62
|
-
template_rows[name] ||= []
|
63
|
-
template_rows[name] << out.gsub("\n", ";").gsub(/\s+/, " ")
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
template_rows = template_rows.sort_by{|name, value| name.to_s}
|
68
|
-
|
69
|
-
output = ''
|
70
|
-
template_rows.each do |template|
|
71
|
-
output << template.first.to_s << "\n\n"
|
72
|
-
table = Terminal::Table.new(:headings => ['Output']) do |t|
|
73
|
-
# template[1] is an array of calls
|
74
|
-
template[1].each do |v|
|
75
|
-
t.add_row [v]
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
output << table.to_s << "\n\n"
|
80
|
-
end
|
81
|
-
|
82
|
-
output
|
83
|
-
end
|
84
|
-
|
85
57
|
def render_array template, headings, value_array, locals
|
86
58
|
return if value_array.empty?
|
87
59
|
|
88
|
-
|
60
|
+
@table.new(:headings => headings) do |t|
|
89
61
|
value_array.each { |value_row| t.add_row value_row }
|
90
62
|
end
|
91
63
|
end
|
@@ -60,12 +60,7 @@ module Brakeman
|
|
60
60
|
end
|
61
61
|
|
62
62
|
@skip_filter_cache.each do |f|
|
63
|
-
if f
|
64
|
-
(f[:only] == method) or
|
65
|
-
(f[:only].is_a? Array and f[:only].include? method) or
|
66
|
-
(f[:except].is_a? Symbol and f[:except] != method) or
|
67
|
-
(f[:except].is_a? Array and not f[:except].include? method)
|
68
|
-
|
63
|
+
if filter_includes_method? f, method
|
69
64
|
filters.concat f[:methods]
|
70
65
|
else
|
71
66
|
end
|
@@ -74,6 +69,7 @@ module Brakeman
|
|
74
69
|
filters
|
75
70
|
end
|
76
71
|
|
72
|
+
|
77
73
|
def remove_skipped_filters processor, filters, method
|
78
74
|
controller = self
|
79
75
|
|
@@ -99,17 +95,11 @@ module Brakeman
|
|
99
95
|
end
|
100
96
|
|
101
97
|
@before_filter_cache.each do |f|
|
102
|
-
if f
|
103
|
-
(f[:only] == method) or
|
104
|
-
(f[:only].is_a? Array and f[:only].include? method) or
|
105
|
-
(f[:except].is_a? Symbol and f[:except] != method) or
|
106
|
-
(f[:except].is_a? Array and not f[:except].include? method)
|
107
|
-
|
98
|
+
if filter_includes_method? f, method
|
108
99
|
filters.concat f[:methods]
|
109
100
|
end
|
110
101
|
end
|
111
102
|
|
112
|
-
|
113
103
|
filters
|
114
104
|
end
|
115
105
|
|
@@ -147,6 +137,16 @@ module Brakeman
|
|
147
137
|
|
148
138
|
filter
|
149
139
|
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
def filter_includes_method? filter_rule, method_name
|
144
|
+
filter_rule[:all] or
|
145
|
+
(filter_rule[:only] == method_name) or
|
146
|
+
(filter_rule[:only].is_a? Array and filter_rule[:only].include? method_name) or
|
147
|
+
(filter_rule[:except].is_a? Symbol and filter_rule[:except] != method_name) or
|
148
|
+
(filter_rule[:except].is_a? Array and not filter_rule[:except].include? method_name)
|
149
|
+
end
|
150
150
|
end
|
151
151
|
|
152
152
|
class Controller < Brakeman::Collection
|
data/lib/brakeman/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: brakeman-lib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.3.
|
4
|
+
version: 3.3.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Collins
|
@@ -9,10 +9,10 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain:
|
11
11
|
- brakeman-public_cert.pem
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-08-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: minitest
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
18
|
- - ">="
|