brakeman-lib 3.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +872 -0
  3. data/FEATURES +16 -0
  4. data/README.md +169 -0
  5. data/WARNING_TYPES +95 -0
  6. data/bin/brakeman +89 -0
  7. data/lib/brakeman.rb +495 -0
  8. data/lib/brakeman/app_tree.rb +161 -0
  9. data/lib/brakeman/brakeman.rake +17 -0
  10. data/lib/brakeman/call_index.rb +219 -0
  11. data/lib/brakeman/checks.rb +191 -0
  12. data/lib/brakeman/checks/base_check.rb +518 -0
  13. data/lib/brakeman/checks/check_basic_auth.rb +88 -0
  14. data/lib/brakeman/checks/check_basic_auth_timing_attack.rb +33 -0
  15. data/lib/brakeman/checks/check_content_tag.rb +160 -0
  16. data/lib/brakeman/checks/check_create_with.rb +75 -0
  17. data/lib/brakeman/checks/check_cross_site_scripting.rb +385 -0
  18. data/lib/brakeman/checks/check_default_routes.rb +86 -0
  19. data/lib/brakeman/checks/check_deserialize.rb +57 -0
  20. data/lib/brakeman/checks/check_detailed_exceptions.rb +55 -0
  21. data/lib/brakeman/checks/check_digest_dos.rb +38 -0
  22. data/lib/brakeman/checks/check_dynamic_finders.rb +49 -0
  23. data/lib/brakeman/checks/check_escape_function.rb +21 -0
  24. data/lib/brakeman/checks/check_evaluation.rb +36 -0
  25. data/lib/brakeman/checks/check_execute.rb +167 -0
  26. data/lib/brakeman/checks/check_file_access.rb +63 -0
  27. data/lib/brakeman/checks/check_file_disclosure.rb +35 -0
  28. data/lib/brakeman/checks/check_filter_skipping.rb +31 -0
  29. data/lib/brakeman/checks/check_forgery_setting.rb +74 -0
  30. data/lib/brakeman/checks/check_header_dos.rb +31 -0
  31. data/lib/brakeman/checks/check_i18n_xss.rb +48 -0
  32. data/lib/brakeman/checks/check_jruby_xml.rb +38 -0
  33. data/lib/brakeman/checks/check_json_encoding.rb +47 -0
  34. data/lib/brakeman/checks/check_json_parsing.rb +107 -0
  35. data/lib/brakeman/checks/check_link_to.rb +132 -0
  36. data/lib/brakeman/checks/check_link_to_href.rb +115 -0
  37. data/lib/brakeman/checks/check_mail_to.rb +49 -0
  38. data/lib/brakeman/checks/check_mass_assignment.rb +198 -0
  39. data/lib/brakeman/checks/check_mime_type_dos.rb +39 -0
  40. data/lib/brakeman/checks/check_model_attr_accessible.rb +55 -0
  41. data/lib/brakeman/checks/check_model_attributes.rb +119 -0
  42. data/lib/brakeman/checks/check_model_serialize.rb +67 -0
  43. data/lib/brakeman/checks/check_nested_attributes.rb +38 -0
  44. data/lib/brakeman/checks/check_nested_attributes_bypass.rb +58 -0
  45. data/lib/brakeman/checks/check_number_to_currency.rb +74 -0
  46. data/lib/brakeman/checks/check_quote_table_name.rb +40 -0
  47. data/lib/brakeman/checks/check_redirect.rb +215 -0
  48. data/lib/brakeman/checks/check_regex_dos.rb +69 -0
  49. data/lib/brakeman/checks/check_render.rb +92 -0
  50. data/lib/brakeman/checks/check_render_dos.rb +37 -0
  51. data/lib/brakeman/checks/check_render_inline.rb +54 -0
  52. data/lib/brakeman/checks/check_response_splitting.rb +21 -0
  53. data/lib/brakeman/checks/check_route_dos.rb +42 -0
  54. data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +31 -0
  55. data/lib/brakeman/checks/check_sanitize_methods.rb +79 -0
  56. data/lib/brakeman/checks/check_secrets.rb +40 -0
  57. data/lib/brakeman/checks/check_select_tag.rb +60 -0
  58. data/lib/brakeman/checks/check_select_vulnerability.rb +60 -0
  59. data/lib/brakeman/checks/check_send.rb +48 -0
  60. data/lib/brakeman/checks/check_send_file.rb +19 -0
  61. data/lib/brakeman/checks/check_session_manipulation.rb +36 -0
  62. data/lib/brakeman/checks/check_session_settings.rb +170 -0
  63. data/lib/brakeman/checks/check_simple_format.rb +59 -0
  64. data/lib/brakeman/checks/check_single_quotes.rb +101 -0
  65. data/lib/brakeman/checks/check_skip_before_filter.rb +60 -0
  66. data/lib/brakeman/checks/check_sql.rb +660 -0
  67. data/lib/brakeman/checks/check_sql_cves.rb +101 -0
  68. data/lib/brakeman/checks/check_ssl_verify.rb +49 -0
  69. data/lib/brakeman/checks/check_strip_tags.rb +89 -0
  70. data/lib/brakeman/checks/check_symbol_dos.rb +64 -0
  71. data/lib/brakeman/checks/check_symbol_dos_cve.rb +30 -0
  72. data/lib/brakeman/checks/check_translate_bug.rb +45 -0
  73. data/lib/brakeman/checks/check_unsafe_reflection.rb +51 -0
  74. data/lib/brakeman/checks/check_unscoped_find.rb +41 -0
  75. data/lib/brakeman/checks/check_validation_regex.rb +116 -0
  76. data/lib/brakeman/checks/check_weak_hash.rb +151 -0
  77. data/lib/brakeman/checks/check_without_protection.rb +80 -0
  78. data/lib/brakeman/checks/check_xml_dos.rb +51 -0
  79. data/lib/brakeman/checks/check_yaml_parsing.rb +121 -0
  80. data/lib/brakeman/differ.rb +66 -0
  81. data/lib/brakeman/file_parser.rb +50 -0
  82. data/lib/brakeman/format/style.css +133 -0
  83. data/lib/brakeman/options.rb +301 -0
  84. data/lib/brakeman/parsers/rails2_erubis.rb +6 -0
  85. data/lib/brakeman/parsers/rails2_xss_plugin_erubis.rb +48 -0
  86. data/lib/brakeman/parsers/rails3_erubis.rb +74 -0
  87. data/lib/brakeman/parsers/template_parser.rb +89 -0
  88. data/lib/brakeman/processor.rb +102 -0
  89. data/lib/brakeman/processors/alias_processor.rb +1013 -0
  90. data/lib/brakeman/processors/base_processor.rb +277 -0
  91. data/lib/brakeman/processors/config_processor.rb +14 -0
  92. data/lib/brakeman/processors/controller_alias_processor.rb +273 -0
  93. data/lib/brakeman/processors/controller_processor.rb +326 -0
  94. data/lib/brakeman/processors/erb_template_processor.rb +80 -0
  95. data/lib/brakeman/processors/erubis_template_processor.rb +104 -0
  96. data/lib/brakeman/processors/gem_processor.rb +57 -0
  97. data/lib/brakeman/processors/haml_template_processor.rb +190 -0
  98. data/lib/brakeman/processors/lib/basic_processor.rb +37 -0
  99. data/lib/brakeman/processors/lib/find_all_calls.rb +223 -0
  100. data/lib/brakeman/processors/lib/find_call.rb +183 -0
  101. data/lib/brakeman/processors/lib/find_return_value.rb +134 -0
  102. data/lib/brakeman/processors/lib/processor_helper.rb +75 -0
  103. data/lib/brakeman/processors/lib/rails2_config_processor.rb +145 -0
  104. data/lib/brakeman/processors/lib/rails2_route_processor.rb +313 -0
  105. data/lib/brakeman/processors/lib/rails3_config_processor.rb +132 -0
  106. data/lib/brakeman/processors/lib/rails3_route_processor.rb +308 -0
  107. data/lib/brakeman/processors/lib/render_helper.rb +181 -0
  108. data/lib/brakeman/processors/lib/render_path.rb +107 -0
  109. data/lib/brakeman/processors/lib/route_helper.rb +68 -0
  110. data/lib/brakeman/processors/lib/safe_call_helper.rb +16 -0
  111. data/lib/brakeman/processors/library_processor.rb +119 -0
  112. data/lib/brakeman/processors/model_processor.rb +191 -0
  113. data/lib/brakeman/processors/output_processor.rb +171 -0
  114. data/lib/brakeman/processors/route_processor.rb +17 -0
  115. data/lib/brakeman/processors/slim_template_processor.rb +107 -0
  116. data/lib/brakeman/processors/template_alias_processor.rb +116 -0
  117. data/lib/brakeman/processors/template_processor.rb +74 -0
  118. data/lib/brakeman/report.rb +78 -0
  119. data/lib/brakeman/report/config/remediation.yml +71 -0
  120. data/lib/brakeman/report/ignore/config.rb +135 -0
  121. data/lib/brakeman/report/ignore/interactive.rb +311 -0
  122. data/lib/brakeman/report/renderer.rb +24 -0
  123. data/lib/brakeman/report/report_base.rb +286 -0
  124. data/lib/brakeman/report/report_codeclimate.rb +70 -0
  125. data/lib/brakeman/report/report_csv.rb +55 -0
  126. data/lib/brakeman/report/report_hash.rb +23 -0
  127. data/lib/brakeman/report/report_html.rb +216 -0
  128. data/lib/brakeman/report/report_json.rb +42 -0
  129. data/lib/brakeman/report/report_markdown.rb +156 -0
  130. data/lib/brakeman/report/report_table.rb +107 -0
  131. data/lib/brakeman/report/report_tabs.rb +17 -0
  132. data/lib/brakeman/report/templates/controller_overview.html.erb +22 -0
  133. data/lib/brakeman/report/templates/controller_warnings.html.erb +21 -0
  134. data/lib/brakeman/report/templates/error_overview.html.erb +29 -0
  135. data/lib/brakeman/report/templates/header.html.erb +58 -0
  136. data/lib/brakeman/report/templates/ignored_warnings.html.erb +25 -0
  137. data/lib/brakeman/report/templates/model_warnings.html.erb +21 -0
  138. data/lib/brakeman/report/templates/overview.html.erb +38 -0
  139. data/lib/brakeman/report/templates/security_warnings.html.erb +23 -0
  140. data/lib/brakeman/report/templates/template_overview.html.erb +21 -0
  141. data/lib/brakeman/report/templates/view_warnings.html.erb +34 -0
  142. data/lib/brakeman/report/templates/warning_overview.html.erb +17 -0
  143. data/lib/brakeman/rescanner.rb +483 -0
  144. data/lib/brakeman/scanner.rb +317 -0
  145. data/lib/brakeman/tracker.rb +347 -0
  146. data/lib/brakeman/tracker/collection.rb +93 -0
  147. data/lib/brakeman/tracker/config.rb +101 -0
  148. data/lib/brakeman/tracker/constants.rb +101 -0
  149. data/lib/brakeman/tracker/controller.rb +161 -0
  150. data/lib/brakeman/tracker/library.rb +17 -0
  151. data/lib/brakeman/tracker/model.rb +90 -0
  152. data/lib/brakeman/tracker/template.rb +33 -0
  153. data/lib/brakeman/util.rb +481 -0
  154. data/lib/brakeman/version.rb +3 -0
  155. data/lib/brakeman/warning.rb +255 -0
  156. data/lib/brakeman/warning_codes.rb +111 -0
  157. data/lib/ruby_parser/bm_sexp.rb +610 -0
  158. data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
  159. metadata +362 -0
@@ -0,0 +1,70 @@
1
+ require "json"
2
+ require "yaml"
3
+
4
+ class Brakeman::Report::CodeClimate < Brakeman::Report::Base
5
+ DOCUMENTATION_PATH = File.expand_path("../../../../docs/warning_types", __FILE__)
6
+ REMEDIATION_POINTS_CONFIG_PATH = File.expand_path("../config/remediation.yml", __FILE__)
7
+ REMEDIATION_POINTS_DEFAULT = 300_000
8
+
9
+ def generate_report
10
+ all_warnings.map { |warning| issue_json(warning) }.join("\0")
11
+ end
12
+
13
+ private
14
+
15
+ def issue_json(warning)
16
+ warning_code_name = name_for(warning.warning_code)
17
+
18
+ {
19
+ type: "Issue",
20
+ check_name: warning_code_name,
21
+ description: warning.message,
22
+ fingerprint: warning.fingerprint,
23
+ categories: ["Security"],
24
+ severity: severity_level_for(warning.confidence),
25
+ remediation_points: remediation_points_for(warning_code_name),
26
+ location: {
27
+ path: warning.relative_path,
28
+ lines: {
29
+ begin: warning.line || 1,
30
+ end: warning.line || 1,
31
+ }
32
+ },
33
+ content: {
34
+ body: content_for(warning.warning_code, warning.link)
35
+ }
36
+ }.to_json
37
+ end
38
+
39
+ def severity_level_for(confidence)
40
+ if confidence == 0
41
+ "critical"
42
+ else
43
+ "normal"
44
+ end
45
+ end
46
+
47
+ def remediation_points_for(warning_code)
48
+ @remediation_points ||= YAML.load_file(REMEDIATION_POINTS_CONFIG_PATH)
49
+ @remediation_points.fetch(name_for(warning_code), REMEDIATION_POINTS_DEFAULT)
50
+ end
51
+
52
+ def name_for(warning_code)
53
+ @warning_codes ||= Brakeman::WarningCodes::Codes.invert
54
+ @warning_codes[warning_code].to_s
55
+ end
56
+
57
+ def content_for(warning_code, link)
58
+ @contents ||= {}
59
+ unless link.nil?
60
+ @contents[warning_code] ||= local_content_for(link) || "Read more: #{link}"
61
+ end
62
+ end
63
+
64
+ def local_content_for(link)
65
+ directory = link.split("/").last
66
+ filename = File.join(DOCUMENTATION_PATH, directory, "index.markdown")
67
+
68
+ File.read(filename) if File.exist?(filename)
69
+ end
70
+ end
@@ -0,0 +1,55 @@
1
+ require 'csv'
2
+ require "brakeman/report/report_table"
3
+
4
+ class Brakeman::Report::CSV < Brakeman::Report::Table
5
+ def generate_report
6
+ output = csv_header
7
+ output << "\nSUMMARY\n"
8
+
9
+ output << table_to_csv(generate_overview) << "\n"
10
+
11
+ output << table_to_csv(generate_warning_overview) << "\n"
12
+
13
+ #Return output early if only summarizing
14
+ if tracker.options[:summary_only]
15
+ return output
16
+ end
17
+
18
+ if tracker.options[:report_routes] or tracker.options[:debug]
19
+ output << "CONTROLLERS\n"
20
+ output << table_to_csv(generate_controllers) << "\n"
21
+ end
22
+
23
+ if tracker.options[:debug]
24
+ output << "TEMPLATES\n\n"
25
+ output << table_to_csv(generate_templates) << "\n"
26
+ end
27
+
28
+ res = generate_errors
29
+ output << "ERRORS\n" << table_to_csv(res) << "\n" if res
30
+
31
+ res = generate_warnings
32
+ output << "SECURITY WARNINGS\n" << table_to_csv(res) << "\n" if res
33
+
34
+ output << "Controller Warnings\n"
35
+ res = generate_controller_warnings
36
+ output << table_to_csv(res) << "\n" if res
37
+
38
+ output << "Model Warnings\n"
39
+ res = generate_model_warnings
40
+ output << table_to_csv(res) << "\n" if res
41
+
42
+ res = generate_template_warnings
43
+ output << "Template Warnings\n"
44
+ output << table_to_csv(res) << "\n" if res
45
+
46
+ output
47
+ end
48
+
49
+ #Generate header for CSV output
50
+ def csv_header
51
+ header = CSV.generate_line(["Application Path", "Report Generation Time", "Checks Performed", "Rails Version"])
52
+ header << CSV.generate_line([File.expand_path(tracker.app_path), Time.now.to_s, checks.checks_run.sort.join(", "), rails_version])
53
+ "BRAKEMAN REPORT\n\n" + header
54
+ end
55
+ end
@@ -0,0 +1,23 @@
1
+ # Generates a hash table for use in Brakeman tests
2
+ class Brakeman::Report::Hash < Brakeman::Report::Base
3
+ def generate_report
4
+ report = { :errors => tracker.errors,
5
+ :controllers => tracker.controllers,
6
+ :models => tracker.models,
7
+ :templates => tracker.templates
8
+ }
9
+
10
+ [:generic_warnings, :controller_warnings, :model_warnings, :template_warnings].each do |meth|
11
+ report[meth] = self.send(meth)
12
+ report[meth].each do |w|
13
+ w.message = w.format_message
14
+ w.context = context_for(@app_tree, w).join("\n")
15
+ end
16
+ end
17
+
18
+ report[:config] = tracker.config
19
+ report[:checks_run] = tracker.checks.checks_run
20
+
21
+ report
22
+ end
23
+ end
@@ -0,0 +1,216 @@
1
+ require 'cgi'
2
+
3
+ class Brakeman::Report::HTML < Brakeman::Report::Base
4
+ HTML_CONFIDENCE = [ "<span class='high-confidence'>High</span>",
5
+ "<span class='med-confidence'>Medium</span>",
6
+ "<span class='weak-confidence'>Weak</span>" ]
7
+
8
+ def initialize *args
9
+ super
10
+
11
+ @element_id = 0 #Used for HTML ids
12
+ end
13
+
14
+ def generate_report
15
+ out = html_header <<
16
+ generate_overview <<
17
+ generate_warning_overview.to_s
18
+
19
+ # Return early if only summarizing
20
+ return out if tracker.options[:summary_only]
21
+
22
+ out << generate_controllers.to_s if tracker.options[:report_routes] or tracker.options[:debug]
23
+ out << generate_templates.to_s if tracker.options[:debug]
24
+ out << generate_errors.to_s
25
+ out << generate_warnings.to_s
26
+ out << generate_controller_warnings.to_s
27
+ out << generate_model_warnings.to_s
28
+ out << generate_template_warnings.to_s
29
+ out << generate_ignored_warnings.to_s
30
+ out << "</body></html>"
31
+ end
32
+
33
+ def generate_overview
34
+ locals = {
35
+ :tracker => tracker,
36
+ :warnings => all_warnings.length,
37
+ :warnings_summary => warnings_summary,
38
+ :number_of_templates => number_of_templates(@tracker),
39
+ :ignored_warnings => ignored_warnings.length
40
+ }
41
+
42
+ Brakeman::Report::Renderer.new('overview', :locals => locals).render
43
+ end
44
+
45
+ #Generate listings of templates and their output
46
+ def generate_templates
47
+ out_processor = Brakeman::OutputProcessor.new
48
+ template_rows = {}
49
+ tracker.templates.each do |name, template|
50
+ template.each_output do |out|
51
+ out = CGI.escapeHTML(out_processor.format(out))
52
+ template_rows[name] ||= []
53
+ template_rows[name] << out.gsub("\n", ";").gsub(/\s+/, " ")
54
+ end
55
+ end
56
+
57
+ template_rows = template_rows.sort_by{|name, value| name.to_s}
58
+
59
+ Brakeman::Report::Renderer.new('template_overview', :locals => {:template_rows => template_rows}).render
60
+ end
61
+
62
+ def render_array template, headings, value_array, locals
63
+ return if value_array.empty?
64
+
65
+ Brakeman::Report::Renderer.new(template, :locals => locals).render
66
+ end
67
+
68
+ def convert_warning warning, original
69
+ warning["Confidence"] = HTML_CONFIDENCE[warning["Confidence"]]
70
+ warning["Message"] = with_context original, warning["Message"]
71
+ warning["Warning Type"] = with_link original, warning["Warning Type"]
72
+ warning
73
+ end
74
+
75
+ def with_link warning, message
76
+ "<a rel=\"no-referrer\" href=\"#{warning.link}\">#{message}</a>"
77
+ end
78
+
79
+ def convert_template_warning warning, original
80
+ warning["Confidence"] = HTML_CONFIDENCE[warning["Confidence"]]
81
+ warning["Message"] = with_context original, warning["Message"]
82
+ warning["Warning Type"] = with_link original, warning["Warning Type"]
83
+ warning["Called From"] = original.called_from
84
+ warning["Template Name"] = original.template.name
85
+ warning
86
+ end
87
+
88
+ def convert_ignored_warning warning, original
89
+ warning = convert_warning(warning, original)
90
+ warning['File'] = original.relative_path
91
+ warning['Note'] = CGI.escapeHTML(@ignore_filter.note_for(original) || "")
92
+ warning
93
+ end
94
+
95
+ #Return header for HTML output. Uses CSS from tracker.options[:html_style]
96
+ def html_header
97
+ if File.exist? tracker.options[:html_style]
98
+ css = File.read tracker.options[:html_style]
99
+ else
100
+ raise "Cannot find CSS stylesheet for HTML: #{tracker.options[:html_style]}"
101
+ end
102
+
103
+ locals = {
104
+ :css => css,
105
+ :tracker => tracker,
106
+ :checks => checks,
107
+ :rails_version => rails_version,
108
+ :brakeman_version => Brakeman::Version
109
+ }
110
+
111
+ Brakeman::Report::Renderer.new('header', :locals => locals).render
112
+ end
113
+
114
+ #Generate HTML for warnings, including context show/hidden via Javascript
115
+ def with_context warning, message
116
+ context = context_for(@app_tree, warning)
117
+ full_message = nil
118
+
119
+ if tracker.options[:message_limit] and tracker.options[:message_limit] > 0 and message.length > tracker.options[:message_limit]
120
+ full_message = html_message(warning, message)
121
+ message = message[0..tracker.options[:message_limit]] << "..."
122
+ end
123
+
124
+ message = html_message(warning, message)
125
+ return message if context.empty? and not full_message
126
+
127
+ @element_id += 1
128
+ code_id = "context#@element_id"
129
+ message_id = "message#@element_id"
130
+ full_message_id = "full_message#@element_id"
131
+ alt = false
132
+ output = "<div class='warning_message' onClick=\"toggle('#{code_id}');toggle('#{message_id}');toggle('#{full_message_id}')\" >" <<
133
+ if full_message
134
+ "<span id='#{message_id}' style='display:block' >#{message}</span>" <<
135
+ "<span id='#{full_message_id}' style='display:none'>#{full_message}</span>"
136
+ else
137
+ message
138
+ end <<
139
+ "<table id='#{code_id}' class='context' style='display:none'>" <<
140
+ "<caption>#{CGI.escapeHTML warning_file(warning) || ''}</caption>"
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
+
152
+ unless context.empty?
153
+ if warning.line - 1 == 1 or warning.line + 1 == 1
154
+ error = " near_error"
155
+ elsif 1 == warning.line
156
+ error = " error"
157
+ else
158
+ error = ""
159
+ end
160
+
161
+ output << <<-HTML
162
+ <tr class='context first#{error}'>
163
+ <td class='context_line'>
164
+ <pre class='context'>#{context.first[0]}</pre>
165
+ </td>
166
+ <td class='context'>
167
+ <pre class='context'>#{CGI.escapeHTML context.first[1].chomp}</pre>
168
+ </td>
169
+ </tr>
170
+ HTML
171
+
172
+ if context.length > 1
173
+ output << context[1..-1].map do |code|
174
+ alt = !alt
175
+ if code[0] == warning.line - 1 or code[0] == warning.line + 1
176
+ error = " near_error"
177
+ elsif code[0] == warning.line
178
+ error = " error"
179
+ else
180
+ error = ""
181
+ end
182
+
183
+ <<-HTML
184
+ <tr class='context#{alt ? ' alt' : ''}#{error}'>
185
+ <td class='context_line'>
186
+ <pre class='context'>#{code[0]}</pre>
187
+ </td>
188
+ <td class='context'>
189
+ <pre class='context'>#{CGI.escapeHTML code[1].chomp}</pre>
190
+ </td>
191
+ </tr>
192
+ HTML
193
+ end.join
194
+ end
195
+ end
196
+
197
+ output << "</tbody></table></div>"
198
+ end
199
+
200
+ #Escape warning message and highlight user input in HTML output
201
+ def html_message warning, message
202
+ message = CGI.escapeHTML(message)
203
+
204
+ if warning.file
205
+ github_url = github_url warning.file, warning.line
206
+ message.gsub!(/(near line \d+)/, "<a href=\"#{github_url}\" target='_blank'>\\1</a>") if github_url
207
+ end
208
+
209
+ if @highlight_user_input and warning.user_input
210
+ user_input = CGI.escapeHTML(warning.format_user_input)
211
+ message.gsub!(user_input, "<span class=\"user_input\">#{user_input}</span>")
212
+ end
213
+
214
+ message
215
+ end
216
+ end
@@ -0,0 +1,42 @@
1
+ class Brakeman::Report::JSON < Brakeman::Report::Base
2
+ def generate_report
3
+ errors = tracker.errors.map{|e| { :error => e[:error], :location => e[:backtrace][0] }}
4
+
5
+ warnings = convert_to_hashes all_warnings
6
+
7
+ ignored = convert_to_hashes ignored_warnings
8
+
9
+ scan_info = {
10
+ :app_path => tracker.app_path,
11
+ :rails_version => rails_version,
12
+ :security_warnings => all_warnings.length,
13
+ :start_time => tracker.start_time.to_s,
14
+ :end_time => tracker.end_time.to_s,
15
+ :duration => tracker.duration,
16
+ :checks_performed => checks.checks_run.sort,
17
+ :number_of_controllers => tracker.controllers.length,
18
+ # ignore the "fake" model
19
+ :number_of_models => tracker.models.length - 1,
20
+ :number_of_templates => number_of_templates(@tracker),
21
+ :ruby_version => RUBY_VERSION,
22
+ :brakeman_version => Brakeman::Version
23
+ }
24
+
25
+ report_info = {
26
+ :scan_info => scan_info,
27
+ :warnings => warnings,
28
+ :ignored_warnings => ignored,
29
+ :errors => errors
30
+ }
31
+
32
+ JSON.pretty_generate report_info
33
+ end
34
+
35
+ def convert_to_hashes warnings
36
+ warnings.map do |w|
37
+ hash = w.to_hash
38
+ hash[:file] = warning_file w
39
+ hash
40
+ end.sort_by { |w| "#{w[:fingerprint]}#{w[:line]}" }
41
+ end
42
+ end
@@ -0,0 +1,156 @@
1
+ Brakeman.load_brakeman_dependency 'terminal-table'
2
+
3
+ class Brakeman::Report::Markdown < Brakeman::Report::Base
4
+
5
+ class MarkdownTable < Terminal::Table
6
+
7
+ def initialize options = {}, &block
8
+ options[:style] ||= {}
9
+ options[:style].merge!({
10
+ :border_x => '-',
11
+ :border_y => '|',
12
+ :border_i => '|'
13
+ })
14
+ super options, &block
15
+ end
16
+
17
+ def render
18
+ super.split("\n")[1...-1].join("\n")
19
+ end
20
+ alias :to_s :render
21
+
22
+ end
23
+
24
+ def generate_report
25
+ out = "# BRAKEMAN REPORT\n\n" <<
26
+ generate_metadata.to_s << "\n\n" <<
27
+ generate_checks.to_s << "\n\n" <<
28
+ "### SUMMARY\n\n" <<
29
+ generate_overview.to_s << "\n\n" <<
30
+ generate_warning_overview.to_s << "\n\n"
31
+
32
+ #Return output early if only summarizing
33
+ return out if tracker.options[:summary_only]
34
+
35
+ if tracker.options[:report_routes] or tracker.options[:debug]
36
+ out << "### CONTROLLERS" << "\n\n" <<
37
+ generate_controllers.to_s << "\n\n"
38
+ end
39
+
40
+ if tracker.options[:debug]
41
+ out << "### TEMPLATES\n\n" <<
42
+ generate_templates.to_s << "\n\n"
43
+ end
44
+
45
+ res = generate_errors
46
+ out << "### Errors\n\n" << res.to_s << "\n\n" if res
47
+
48
+ res = generate_warnings
49
+ out << "### SECURITY WARNINGS\n\n" << res.to_s << "\n\n" if res
50
+
51
+ res = generate_controller_warnings
52
+ out << "### Controller Warnings:\n\n" << res.to_s << "\n\n" if res
53
+
54
+ res = generate_model_warnings
55
+ out << "### Model Warnings:\n\n" << res.to_s << "\n\n" if res
56
+
57
+ res = generate_template_warnings
58
+ out << "### View Warnings:\n\n" << res.to_s << "\n\n" if res
59
+
60
+ out
61
+ end
62
+
63
+ def generate_metadata
64
+ MarkdownTable.new(
65
+ :headings =>
66
+ ['Application path', 'Rails version', 'Brakeman version', 'Started at', 'Duration']
67
+ ) do |t|
68
+ t.add_row([
69
+ tracker.app_path,
70
+ rails_version,
71
+ Brakeman::Version,
72
+ tracker.start_time,
73
+ "#{tracker.duration} seconds",
74
+ ])
75
+ end
76
+ end
77
+
78
+ def generate_checks
79
+ MarkdownTable.new(:headings => ['Checks performed']) do |t|
80
+ t.add_row([checks.checks_run.sort.join(", ")])
81
+ end
82
+ end
83
+
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
+ def convert_warning warning, original
136
+ warning["Confidence"] = TEXT_CONFIDENCE[warning["Confidence"]]
137
+ warning["Message"] = markdown_message original, warning["Message"]
138
+ warning["Warning Type"] = "[#{warning['Warning Type']}](#{original.link})" if original.link
139
+ warning
140
+ end
141
+
142
+ # Escape and code format warning message
143
+ def markdown_message warning, message
144
+ if warning.file
145
+ github_url = github_url warning.file, warning.line
146
+ message.gsub!(/(near line \d+)/, "[\\1](#{github_url})") if github_url
147
+ end
148
+ if warning.code
149
+ code = warning.format_code
150
+ message.gsub(code, "`#{code.gsub('`','``').gsub(/\A``|``\z/, '` `')}`")
151
+ else
152
+ message
153
+ end
154
+ end
155
+
156
+ end