brakeman-lib 3.3.1

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 (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