brakeman 4.10.0 → 5.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (197) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +46 -0
  3. data/README.md +11 -2
  4. data/bundle/load.rb +5 -3
  5. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/CHANGELOG.md +16 -0
  6. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/FAQ.md +0 -0
  7. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/Gemfile +1 -4
  8. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/MIT-LICENSE +0 -0
  9. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/README.md +2 -3
  10. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/REFERENCE.md +29 -7
  11. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/TODO +0 -0
  12. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/haml.gemspec +2 -1
  13. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml.rb +0 -0
  14. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/attribute_builder.rb +3 -3
  15. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/attribute_compiler.rb +42 -31
  16. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/attribute_parser.rb +0 -0
  17. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/buffer.rb +0 -0
  18. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/compiler.rb +0 -0
  19. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/engine.rb +0 -0
  20. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/error.rb +0 -0
  21. data/bundle/ruby/2.7.0/gems/haml-5.2.1/lib/haml/escapable.rb +77 -0
  22. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/exec.rb +0 -0
  23. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/filters.rb +0 -0
  24. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/generator.rb +0 -0
  25. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/helpers.rb +7 -1
  26. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/helpers/action_view_extensions.rb +0 -0
  27. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/helpers/action_view_mods.rb +0 -0
  28. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/helpers/action_view_xss_mods.rb +0 -0
  29. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/helpers/safe_erubi_template.rb +0 -0
  30. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/helpers/safe_erubis_template.rb +0 -0
  31. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/helpers/xss_mods.rb +6 -3
  32. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/options.rb +0 -0
  33. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/parser.rb +32 -4
  34. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/plugin.rb +0 -0
  35. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/railtie.rb +0 -0
  36. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/sass_rails_filter.rb +0 -0
  37. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/template.rb +0 -0
  38. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/template/options.rb +0 -0
  39. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/temple_engine.rb +0 -0
  40. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/temple_line_counter.rb +0 -0
  41. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/util.rb +1 -1
  42. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/version.rb +1 -1
  43. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/yard/default/fulldoc/html/css/common.sass +0 -0
  44. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/yard/default/layout/html/footer.erb +0 -0
  45. data/bundle/ruby/2.7.0/gems/parallel-1.20.1/MIT-LICENSE.txt +20 -0
  46. data/bundle/ruby/2.7.0/gems/parallel-1.20.1/lib/parallel.rb +523 -0
  47. data/bundle/ruby/2.7.0/gems/parallel-1.20.1/lib/parallel/processor_count.rb +42 -0
  48. data/bundle/ruby/2.7.0/gems/parallel-1.20.1/lib/parallel/version.rb +3 -0
  49. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/LICENSE.txt +22 -0
  50. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/NEWS.md +178 -0
  51. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/README.md +48 -0
  52. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml.rb +3 -0
  53. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/attlistdecl.rb +63 -0
  54. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/attribute.rb +205 -0
  55. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/cdata.rb +68 -0
  56. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/child.rb +97 -0
  57. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/comment.rb +80 -0
  58. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/doctype.rb +311 -0
  59. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/document.rb +451 -0
  60. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/dtd/attlistdecl.rb +11 -0
  61. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/dtd/dtd.rb +47 -0
  62. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/dtd/elementdecl.rb +18 -0
  63. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/dtd/entitydecl.rb +57 -0
  64. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/dtd/notationdecl.rb +40 -0
  65. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/element.rb +2599 -0
  66. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/encoding.rb +51 -0
  67. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/entity.rb +171 -0
  68. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/formatters/default.rb +116 -0
  69. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/formatters/pretty.rb +142 -0
  70. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/formatters/transitive.rb +58 -0
  71. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/functions.rb +447 -0
  72. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/instruction.rb +79 -0
  73. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/light/node.rb +188 -0
  74. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/namespace.rb +59 -0
  75. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/node.rb +76 -0
  76. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/output.rb +30 -0
  77. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/parent.rb +166 -0
  78. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/parseexception.rb +52 -0
  79. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/parsers/baseparser.rb +694 -0
  80. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/parsers/lightparser.rb +59 -0
  81. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/parsers/pullparser.rb +197 -0
  82. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/parsers/sax2parser.rb +273 -0
  83. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/parsers/streamparser.rb +61 -0
  84. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/parsers/treeparser.rb +101 -0
  85. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/parsers/ultralightparser.rb +57 -0
  86. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/parsers/xpathparser.rb +689 -0
  87. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/quickpath.rb +266 -0
  88. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/rexml.rb +37 -0
  89. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/sax2listener.rb +98 -0
  90. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/security.rb +28 -0
  91. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/source.rb +298 -0
  92. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/streamlistener.rb +93 -0
  93. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/text.rb +424 -0
  94. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/undefinednamespaceexception.rb +9 -0
  95. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/validation/relaxng.rb +539 -0
  96. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/validation/validation.rb +144 -0
  97. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/validation/validationexception.rb +10 -0
  98. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/xmldecl.rb +130 -0
  99. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/xmltokens.rb +85 -0
  100. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/xpath.rb +81 -0
  101. data/bundle/ruby/2.7.0/gems/rexml-3.2.5/lib/rexml/xpath_parser.rb +974 -0
  102. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/History.rdoc +25 -0
  103. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/Manifest.txt +2 -0
  104. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/README.rdoc +0 -0
  105. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/compare/normalize.rb +2 -2
  106. data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/debugging.md +190 -0
  107. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/rp_extensions.rb +0 -0
  108. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/rp_stringscanner.rb +0 -0
  109. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby20_parser.rb +2392 -2384
  110. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby20_parser.y +6 -1
  111. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby21_parser.rb +2553 -2550
  112. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby21_parser.y +6 -1
  113. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby22_parser.rb +2491 -2471
  114. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby22_parser.y +6 -1
  115. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby23_parser.rb +2422 -2403
  116. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby23_parser.y +6 -1
  117. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby24_parser.rb +2460 -2450
  118. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby24_parser.y +6 -1
  119. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby25_parser.rb +2450 -2441
  120. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby25_parser.y +6 -1
  121. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby26_parser.rb +2444 -2433
  122. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby26_parser.y +7 -1
  123. data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby27_parser.rb +7310 -0
  124. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby27_parser.y +21 -1
  125. data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby30_parser.rb +7310 -0
  126. data/bundle/ruby/2.7.0/gems/ruby_parser-3.16.0/lib/ruby30_parser.y +2677 -0
  127. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby_lexer.rb +19 -0
  128. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby_lexer.rex +1 -1
  129. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby_lexer.rex.rb +1 -1
  130. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby_parser.rb +2 -0
  131. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby_parser.yy +27 -1
  132. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/lib/ruby_parser_extras.rb +2 -2
  133. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/tools/munge.rb +2 -2
  134. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.16.0}/tools/ripper.rb +0 -0
  135. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/History.rdoc +12 -0
  136. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/Manifest.txt +0 -0
  137. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/README.rdoc +0 -0
  138. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/lib/composite_sexp_processor.rb +0 -0
  139. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/lib/pt_testcase.rb +2 -2
  140. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/lib/sexp.rb +0 -0
  141. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/lib/sexp_matcher.rb +0 -0
  142. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/lib/sexp_processor.rb +1 -1
  143. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/lib/strict_sexp.rb +0 -0
  144. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.3}/lib/unique.rb +0 -0
  145. data/lib/brakeman.rb +21 -4
  146. data/lib/brakeman/app_tree.rb +36 -3
  147. data/lib/brakeman/checks/base_check.rb +7 -1
  148. data/lib/brakeman/checks/check_detailed_exceptions.rb +1 -1
  149. data/lib/brakeman/checks/check_evaluation.rb +1 -1
  150. data/lib/brakeman/checks/check_execute.rb +2 -1
  151. data/lib/brakeman/checks/check_mass_assignment.rb +4 -6
  152. data/lib/brakeman/checks/check_regex_dos.rb +1 -1
  153. data/lib/brakeman/checks/check_sanitize_methods.rb +2 -1
  154. data/lib/brakeman/checks/check_sql.rb +16 -3
  155. data/lib/brakeman/checks/check_unsafe_reflection_methods.rb +68 -0
  156. data/lib/brakeman/checks/check_verb_confusion.rb +75 -0
  157. data/lib/brakeman/file_parser.rb +50 -22
  158. data/lib/brakeman/options.rb +5 -1
  159. data/lib/brakeman/parsers/template_parser.rb +26 -3
  160. data/lib/brakeman/processors/alias_processor.rb +91 -19
  161. data/lib/brakeman/processors/base_processor.rb +4 -4
  162. data/lib/brakeman/processors/controller_alias_processor.rb +6 -43
  163. data/lib/brakeman/processors/controller_processor.rb +1 -1
  164. data/lib/brakeman/processors/haml_template_processor.rb +8 -1
  165. data/lib/brakeman/processors/lib/call_conversion_helper.rb +10 -0
  166. data/lib/brakeman/processors/lib/file_type_detector.rb +64 -0
  167. data/lib/brakeman/processors/lib/rails3_config_processor.rb +16 -16
  168. data/lib/brakeman/processors/lib/rails4_config_processor.rb +2 -1
  169. data/lib/brakeman/processors/library_processor.rb +9 -0
  170. data/lib/brakeman/processors/output_processor.rb +1 -1
  171. data/lib/brakeman/processors/template_alias_processor.rb +5 -0
  172. data/lib/brakeman/report.rb +12 -1
  173. data/lib/brakeman/report/ignore/interactive.rb +1 -1
  174. data/lib/brakeman/report/report_base.rb +0 -2
  175. data/lib/brakeman/report/report_csv.rb +37 -60
  176. data/lib/brakeman/report/report_github.rb +31 -0
  177. data/lib/brakeman/report/report_junit.rb +2 -2
  178. data/lib/brakeman/report/report_sarif.rb +1 -1
  179. data/lib/brakeman/report/report_sonar.rb +38 -0
  180. data/lib/brakeman/report/report_tabs.rb +1 -1
  181. data/lib/brakeman/report/report_text.rb +1 -1
  182. data/lib/brakeman/rescanner.rb +7 -5
  183. data/lib/brakeman/scanner.rb +47 -18
  184. data/lib/brakeman/tracker.rb +39 -4
  185. data/lib/brakeman/tracker/collection.rb +27 -5
  186. data/lib/brakeman/tracker/config.rb +73 -0
  187. data/lib/brakeman/tracker/controller.rb +1 -1
  188. data/lib/brakeman/tracker/method_info.rb +29 -0
  189. data/lib/brakeman/util.rb +17 -4
  190. data/lib/brakeman/version.rb +1 -1
  191. data/lib/brakeman/warning.rb +10 -2
  192. data/lib/brakeman/warning_codes.rb +2 -0
  193. data/lib/ruby_parser/bm_sexp.rb +9 -9
  194. metadata +149 -84
  195. data/bundle/ruby/2.7.0/gems/haml-5.1.2/lib/haml/escapable.rb +0 -50
  196. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.0/debugging.md +0 -57
  197. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.0/lib/ruby27_parser.rb +0 -7224
@@ -29,7 +29,7 @@ class Brakeman::CheckRegexDoS < Brakeman::BaseCheck
29
29
  return unless original? result
30
30
 
31
31
  call = result[:call]
32
- components = call[1..-1]
32
+ components = call.sexp_body
33
33
 
34
34
  components.any? do |component|
35
35
  next unless sexp? component
@@ -90,7 +90,8 @@ class Brakeman::CheckSanitizeMethods < Brakeman::BaseCheck
90
90
  def loofah_vulnerable_cve_2018_8048?
91
91
  loofah_version = tracker.config.gem_version(:loofah)
92
92
 
93
- loofah_version and loofah_version < "2.2.1"
93
+ # 2.2.1 is fix version
94
+ loofah_version and version_between?("0.0.0", "2.2.0", loofah_version)
94
95
  end
95
96
 
96
97
  def warn_sanitizer_cve cve, link, upgrade_version
@@ -572,11 +572,11 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
572
572
  end
573
573
 
574
574
  IGNORE_METHODS_IN_SQL = Set[:id, :merge_conditions, :table_name, :quoted_table_name,
575
- :quoted_primary_key, :to_i, :to_f, :sanitize_sql, :sanitize_sql_array,
575
+ :quoted_primary_key, :to_i, :to_f, :sanitize_sql, :sanitize_sql_array, :sanitize_sql_like,
576
576
  :sanitize_sql_for_assignment, :sanitize_sql_for_conditions, :sanitize_sql_hash,
577
577
  :sanitize_sql_hash_for_assignment, :sanitize_sql_hash_for_conditions,
578
578
  :to_sql, :sanitize, :primary_key, :table_name_prefix, :table_name_suffix,
579
- :where_values_hash, :foreign_key
579
+ :where_values_hash, :foreign_key, :uuid
580
580
  ]
581
581
 
582
582
  def safe_value? exp
@@ -592,7 +592,8 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
592
592
  IGNORE_METHODS_IN_SQL.include? exp.method or
593
593
  quote_call? exp or
594
594
  arel? exp or
595
- exp.method.to_s.end_with? "_id"
595
+ exp.method.to_s.end_with? "_id" or
596
+ number_target? exp
596
597
  end
597
598
  when :if
598
599
  safe_value? exp.then_clause and safe_value? exp.else_clause
@@ -695,4 +696,16 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
695
696
  active_record_models.include? klass
696
697
  end
697
698
  end
699
+
700
+ def number_target? exp
701
+ return unless call? exp
702
+
703
+ if number? exp.target
704
+ true
705
+ elsif call? exp.target
706
+ number_target? exp.target
707
+ else
708
+ false
709
+ end
710
+ end
698
711
  end
@@ -0,0 +1,68 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckUnsafeReflectionMethods < Brakeman::BaseCheck
4
+ Brakeman::Checks.add self
5
+
6
+ @description = "Checks for unsafe reflection to access methods"
7
+
8
+ def run_check
9
+ check_method
10
+ check_tap
11
+ check_to_proc
12
+ end
13
+
14
+ def check_method
15
+ tracker.find_call(method: :method, nested: true).each do |result|
16
+ argument = result[:call].first_arg
17
+
18
+ if user_input = include_user_input?(argument)
19
+ warn_unsafe_reflection(result, user_input)
20
+ end
21
+ end
22
+ end
23
+
24
+ def check_tap
25
+ tracker.find_call(method: :tap, nested: true).each do |result|
26
+ argument = result[:call].first_arg
27
+
28
+ # Argument is passed like a.tap(&argument)
29
+ if node_type? argument, :block_pass
30
+ argument = argument.value
31
+ end
32
+
33
+ if user_input = include_user_input?(argument)
34
+ warn_unsafe_reflection(result, user_input)
35
+ end
36
+ end
37
+ end
38
+
39
+ def check_to_proc
40
+ tracker.find_call(method: :to_proc, nested: true).each do |result|
41
+ target = result[:call].target
42
+
43
+ if user_input = include_user_input?(target)
44
+ warn_unsafe_reflection(result, user_input)
45
+ end
46
+ end
47
+ end
48
+
49
+ def warn_unsafe_reflection result, input
50
+ return unless original? result
51
+ method = result[:call].method
52
+
53
+ confidence = if input.type == :params
54
+ :high
55
+ else
56
+ :medium
57
+ end
58
+
59
+ message = msg("Unsafe reflection method ", msg_code(method), " called with ", msg_input(input))
60
+
61
+ warn :result => result,
62
+ :warning_type => "Remote Code Execution",
63
+ :warning_code => :unsafe_method_reflection,
64
+ :message => message,
65
+ :user_input => input,
66
+ :confidence => confidence
67
+ end
68
+ end
@@ -0,0 +1,75 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckVerbConfusion < Brakeman::BaseCheck
4
+ Brakeman::Checks.add self
5
+
6
+ @description = "Check for uses of `request.get?` that might have unintentional behavior"
7
+
8
+ #Process calls
9
+ def run_check
10
+ calls = tracker.find_call(target: :request, methods: [:get?])
11
+
12
+ calls.each do |call|
13
+ process_result call
14
+ end
15
+ end
16
+
17
+ def process_result result
18
+ @current_result = result
19
+ @matched_call = result[:call]
20
+ klass = tracker.find_class(result[:location][:class])
21
+
22
+ # TODO: abstract into tracker.find_location ?
23
+ if klass.nil?
24
+ Brakeman.debug "No class found: #{result[:location][:class]}"
25
+ return
26
+ end
27
+
28
+ method = klass.get_method(result[:location][:method])
29
+
30
+ if method.nil?
31
+ Brakeman.debug "No method found: #{result[:location][:method]}"
32
+ return
33
+ end
34
+
35
+ process method.src
36
+ end
37
+
38
+ def process_if exp
39
+ if exp.condition == @matched_call
40
+ # Found `if request.get?`
41
+
42
+ # Do not warn if there is an `elsif` clause
43
+ if node_type? exp.else_clause, :if
44
+ return exp
45
+ end
46
+
47
+ warn_about_result @current_result, exp
48
+ end
49
+
50
+ exp
51
+ end
52
+
53
+ def warn_about_result result, code
54
+ return unless original? result
55
+
56
+ confidence = :weak
57
+ message = msg('Potential HTTP verb confusion. ',
58
+ msg_code('HEAD'),
59
+ ' is routed like ',
60
+ msg_code('GET'),
61
+ ' but ',
62
+ msg_code('request.get?'),
63
+ ' will return ',
64
+ msg_code('false')
65
+ )
66
+
67
+ warn :result => result,
68
+ :warning_type => "HTTP Verb Confusion",
69
+ :warning_code => :http_verb_confusion,
70
+ :message => message,
71
+ :code => code,
72
+ :user_input => result[:call],
73
+ :confidence => confidence
74
+ end
75
+ end
@@ -1,51 +1,79 @@
1
+ require 'parallel'
2
+
1
3
  module Brakeman
2
4
  ASTFile = Struct.new(:path, :ast)
3
5
 
4
6
  # This class handles reading and parsing files.
5
7
  class FileParser
6
- attr_reader :file_list
8
+ attr_reader :file_list, :errors
7
9
 
8
- def initialize tracker
9
- @tracker = tracker
10
- @timeout = @tracker.options[:parser_timeout]
11
- @app_tree = @tracker.app_tree
12
- @file_list = {}
10
+ def initialize app_tree, timeout
11
+ @app_tree = app_tree
12
+ @timeout = timeout
13
+ @file_list = []
14
+ @errors = []
13
15
  end
14
16
 
15
- def parse_files list, type
16
- read_files list, type do |path, contents|
17
- if ast = parse_ruby(contents, path.relative)
18
- ASTFile.new(path, ast)
17
+ def parse_files list
18
+ # Parse the files in parallel.
19
+ # By default, the parsing will be in separate processes.
20
+ # So we map the result to ASTFiles and/or Exceptions
21
+ # then partition them into ASTFiles and Exceptions
22
+ # and add the Exceptions to @errors
23
+ #
24
+ # Basically just a funky way to deal with two possible
25
+ # return types that are returned from isolated processes.
26
+ #
27
+ # Note this method no longer uses read_files
28
+ @file_list, new_errors = Parallel.map(list) do |file_name|
29
+ file_path = @app_tree.file_path(file_name)
30
+ contents = file_path.read
31
+
32
+ begin
33
+ if ast = parse_ruby(contents, file_path.relative)
34
+ ASTFile.new(file_name, ast)
35
+ end
36
+ rescue Exception => e
37
+ e
19
38
  end
39
+ end.compact.partition do |result|
40
+ result.is_a? ASTFile
20
41
  end
21
- end
22
42
 
23
- def read_files list, type
24
- @file_list[type] ||= []
43
+ errors.concat new_errors
44
+ end
25
45
 
46
+ def read_files list
26
47
  list.each do |path|
27
48
  file = @app_tree.file_path(path)
28
49
 
29
- result = yield file, file.read
30
- if result
31
- @file_list[type] << result
50
+ begin
51
+ result = yield file, file.read
52
+
53
+ if result
54
+ @file_list << result
55
+ end
56
+ rescue Exception => e
57
+ @errors << e
32
58
  end
33
59
  end
34
60
  end
35
61
 
62
+ # _path_ can be a string or a Brakeman::FilePath
36
63
  def parse_ruby input, path
64
+ if path.is_a? Brakeman::FilePath
65
+ path = path.relative
66
+ end
67
+
37
68
  begin
38
69
  Brakeman.debug "Parsing #{path}"
39
70
  RubyParser.new.parse input, path, @timeout
40
71
  rescue Racc::ParseError => e
41
- @tracker.error e, "Could not parse #{path}"
42
- nil
72
+ raise e.exception(e.message + "\nCould not parse #{path}")
43
73
  rescue Timeout::Error => e
44
- @tracker.error Exception.new("Parsing #{path} took too long (> #{@timeout} seconds). Try increasing the limit with --parser-timeout"), caller
45
- nil
74
+ raise Exception.new("Parsing #{path} took too long (> #{@timeout} seconds). Try increasing the limit with --parser-timeout")
46
75
  rescue => e
47
- @tracker.error e.exception(e.message + "\nWhile processing #{path}"), e.backtrace
48
- nil
76
+ raise e.exception(e.message + "\nWhile processing #{path}")
49
77
  end
50
78
  end
51
79
  end
@@ -166,6 +166,10 @@ module Brakeman::Options
166
166
  options[:only_files].merge files
167
167
  end
168
168
 
169
+ opts.on "--[no-]skip-vendor", "Skip processing vendor directory (Default)" do |skip|
170
+ options[:skip_vendor] = skip
171
+ end
172
+
169
173
  opts.on "--skip-libs", "Skip processing lib directory" do
170
174
  options[:skip_libs] = true
171
175
  end
@@ -229,7 +233,7 @@ module Brakeman::Options
229
233
 
230
234
  opts.on "-f",
231
235
  "--format TYPE",
232
- [:pdf, :text, :html, :csv, :tabs, :json, :markdown, :codeclimate, :cc, :plain, :table, :junit, :sarif],
236
+ [:pdf, :text, :html, :csv, :tabs, :json, :markdown, :codeclimate, :cc, :plain, :table, :junit, :sarif, :sonar, :github],
233
237
  "Specify output formats. Default is text" do |type|
234
238
 
235
239
  type = "s" if type == :text
@@ -9,7 +9,7 @@ module Brakeman
9
9
  def initialize tracker, file_parser
10
10
  @tracker = tracker
11
11
  @file_parser = file_parser
12
- @file_parser.file_list[:templates] ||= []
12
+ @slim_smart = nil # Load slim/smart ?
13
13
  end
14
14
 
15
15
  def parse_template path, text
@@ -33,7 +33,7 @@ module Brakeman
33
33
  end
34
34
 
35
35
  if src and ast = @file_parser.parse_ruby(src, path)
36
- @file_parser.file_list[:templates] << TemplateFile.new(path, ast, name, type)
36
+ @file_parser.file_list << TemplateFile.new(path, ast, name, type)
37
37
  end
38
38
  rescue Racc::ParseError => e
39
39
  tracker.error e, "Could not parse #{path}"
@@ -89,6 +89,14 @@ module Brakeman
89
89
 
90
90
  def parse_slim path, text
91
91
  Brakeman.load_brakeman_dependency 'slim'
92
+
93
+ if @slim_smart.nil? and load_slim_smart?
94
+ @slim_smart = true
95
+ Brakeman.load_brakeman_dependency 'slim/smart'
96
+ else
97
+ @slim_smart = false
98
+ end
99
+
92
100
  require_relative 'slim_embedded'
93
101
 
94
102
  Slim::Template.new(path,
@@ -96,8 +104,23 @@ module Brakeman
96
104
  :generator => Temple::Generators::RailsOutputBuffer) { text }.precompiled_template
97
105
  end
98
106
 
107
+ def load_slim_smart?
108
+ return !@slim_smart unless @slim_smart.nil?
109
+
110
+ # Terrible hack to find
111
+ # gem "slim", "~> 3.0.1", require: ["slim", "slim/smart"]
112
+ if tracker.app_tree.exists? 'Gemfile'
113
+ gemfile_contents = tracker.app_tree.file_path('Gemfile').read
114
+ if gemfile_contents.include? 'slim/smart'
115
+ return true
116
+ end
117
+ end
118
+
119
+ false
120
+ end
121
+
99
122
  def self.parse_inline_erb tracker, text
100
- fp = Brakeman::FileParser.new(tracker)
123
+ fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout])
101
124
  tp = self.new(tracker, fp)
102
125
  src = tp.parse_erb '_inline_', text
103
126
  type = tp.erubis? ? :erubis : :erb
@@ -161,6 +161,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
161
161
  ARRAY_CONST = s(:const, :Array)
162
162
  HASH_CONST = s(:const, :Hash)
163
163
  RAILS_TEST = s(:call, s(:call, s(:const, :Rails), :env), :test?)
164
+ RAILS_DEV = s(:call, s(:call, s(:const, :Rails), :env), :development?)
164
165
 
165
166
  #Process a method call.
166
167
  def process_call exp
@@ -182,11 +183,17 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
182
183
  return exp
183
184
  end
184
185
 
186
+ # If x(*[1,2,3]) change to x(1,2,3)
187
+ # if that's the only argument
188
+ if splat_array? exp.first_arg and exp.second_arg.nil?
189
+ exp.arglist = exp.first_arg[1].sexp_body
190
+ end
191
+
185
192
  target = exp.target
186
193
  method = exp.method
187
194
  first_arg = exp.first_arg
188
195
 
189
- if method == :send or method == :try
196
+ if method == :send or method == :__send__ or method == :try
190
197
  collapse_send_call exp, first_arg
191
198
  end
192
199
 
@@ -194,11 +201,11 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
194
201
  res = process_or_simple_operation(exp)
195
202
  return res if res
196
203
  elsif target == ARRAY_CONST and method == :new
197
- return Sexp.new(:array, *exp.args)
204
+ return Sexp.new(:array, *exp.args).line(exp.line)
198
205
  elsif target == HASH_CONST and method == :new and first_arg.nil? and !node_type?(@exp_context.last, :iter)
199
- return Sexp.new(:hash)
200
- elsif exp == RAILS_TEST
201
- return Sexp.new(:false)
206
+ return Sexp.new(:hash).line(exp.line)
207
+ elsif exp == RAILS_TEST or exp == RAILS_DEV
208
+ return Sexp.new(:false).line(exp.line)
202
209
  end
203
210
 
204
211
  #See if it is possible to simplify some basic cases
@@ -213,13 +220,28 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
213
220
  exp = math_op(:+, target, first_arg, exp)
214
221
  end
215
222
  when :-, :*, :/
216
- exp = math_op(method, target, first_arg, exp)
223
+ if method == :* and array? target
224
+ if string? first_arg
225
+ exp = process_array_join(target, first_arg)
226
+ end
227
+ else
228
+ exp = math_op(method, target, first_arg, exp)
229
+ end
217
230
  when :[]
218
231
  if array? target
219
232
  exp = process_array_access(target, exp.args, exp)
220
233
  elsif hash? target
221
234
  exp = process_hash_access(target, first_arg, exp)
222
235
  end
236
+ when :fetch
237
+ if array? target
238
+ # Not dealing with default value
239
+ # so just pass in first argument, but process_array_access expects
240
+ # an array of arguments.
241
+ exp = process_array_access(target, [first_arg], exp)
242
+ elsif hash? target
243
+ exp = process_hash_access(target, first_arg, exp)
244
+ end
223
245
  when :merge!, :update
224
246
  if hash? target and hash? first_arg
225
247
  target = process_hash_merge! target, first_arg
@@ -236,7 +258,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
236
258
  env[target_var] = target
237
259
  return target
238
260
  elsif string? target and string_interp? first_arg
239
- exp = Sexp.new(:dstr, target.value + first_arg[1]).concat(first_arg[2..-1])
261
+ exp = Sexp.new(:dstr, target.value + first_arg[1]).concat(first_arg.sexp_body(2)).line(exp.line)
240
262
  env[target_var] = exp
241
263
  elsif string? first_arg and string_interp? target
242
264
  if string? target.last
@@ -259,6 +281,12 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
259
281
  target = find_push_target(target_var)
260
282
  env[target] = exp unless target.nil? # Happens in TemplateAliasProcessor
261
283
  end
284
+ when :push
285
+ if array? target
286
+ target << first_arg
287
+ env[target_var] = target
288
+ return target
289
+ end
262
290
  when :first
263
291
  if array? target and first_arg.nil? and sexp? target[1]
264
292
  exp = target[1]
@@ -272,7 +300,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
272
300
  exp = target
273
301
  end
274
302
  when :join
275
- if array? target and target.length > 2 and (string? first_arg or first_arg.nil?)
303
+ if array? target and (string? first_arg or first_arg.nil?)
276
304
  exp = process_array_join(target, first_arg)
277
305
  end
278
306
  when :!
@@ -280,6 +308,15 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
280
308
  if call? target and target.method == :!
281
309
  exp = s(:or, s(:true).line(exp.line), s(:false).line(exp.line)).line(exp.line)
282
310
  end
311
+ when :values
312
+ # Hash literal
313
+ if node_type? target, :hash
314
+ exp = hash_values(target)
315
+ end
316
+ when :values_at
317
+ if hash? target
318
+ exp = hash_values_at target, exp.args
319
+ end
283
320
  end
284
321
 
285
322
  exp
@@ -287,7 +324,12 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
287
324
 
288
325
  # Painful conversion of Array#join into string interpolation
289
326
  def process_array_join array, join_str
290
- result = s()
327
+ # Empty array
328
+ if array.length == 1
329
+ return s(:str, '').line(array.line)
330
+ end
331
+
332
+ result = s().line(array.line)
291
333
 
292
334
  join_value = if string? join_str
293
335
  join_str.value
@@ -295,8 +337,10 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
295
337
  nil
296
338
  end
297
339
 
298
- array[1..-2].each do |e|
299
- result << join_item(e, join_value)
340
+ if array.length > 2
341
+ array[1..-2].each do |e|
342
+ result << join_item(e, join_value)
343
+ end
300
344
  end
301
345
 
302
346
  result << join_item(array.last, nil)
@@ -325,27 +369,52 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
325
369
  result.unshift combined_first
326
370
 
327
371
  # Have to fix up strings that follow interpolation
328
- result.reduce(s(:dstr)) do |memo, e|
372
+ string = result.reduce(s(:dstr).line(array.line)) do |memo, e|
329
373
  if string? e and node_type? memo.last, :evstr
330
374
  e.value = "#{join_value}#{e.value}"
331
375
  elsif join_value and node_type? memo.last, :evstr and node_type? e, :evstr
332
- memo << s(:str, join_value)
376
+ memo << s(:str, join_value).line(e.line)
333
377
  end
334
378
 
335
379
  memo << e
336
380
  end
381
+
382
+ # Convert (:dstr, "hello world")
383
+ # to (:str, "hello world")
384
+ if string.length == 2 and string.last.is_a? String
385
+ string[0] = :str
386
+ end
387
+
388
+ string
337
389
  end
338
390
 
339
391
  def join_item item, join_value
340
392
  if item.is_a? String
341
393
  "#{item}#{join_value}"
342
394
  elsif string? item or symbol? item or number? item
343
- s(:str, "#{item.value}#{join_value}")
395
+ s(:str, "#{item.value}#{join_value}").line(item.line)
344
396
  else
345
- s(:evstr, item)
397
+ s(:evstr, item).line(item.line)
346
398
  end
347
399
  end
348
400
 
401
+ TEMP_FILE_CLASS = s(:const, :Tempfile)
402
+
403
+ def temp_file_open? exp
404
+ call? exp and
405
+ exp.target == TEMP_FILE_CLASS and
406
+ exp.method == :open
407
+ end
408
+
409
+ def temp_file_new line
410
+ s(:call, TEMP_FILE_CLASS, :new).line(line)
411
+ end
412
+
413
+ def splat_array? exp
414
+ node_type? exp, :splat and
415
+ node_type? exp[1], :array
416
+ end
417
+
349
418
  def process_iter exp
350
419
  @exp_context.push exp
351
420
  exp[1] = process exp.block_call
@@ -363,6 +432,9 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
363
432
  # Iterating over an array of all literal values
364
433
  local = Sexp.new(:lvar, block_args.last)
365
434
  env.current[local] = safe_literal(exp.line)
435
+ elsif temp_file_open? call
436
+ local = Sexp.new(:lvar, block_args.last)
437
+ env.current[local] = temp_file_new(exp.line)
366
438
  else
367
439
  block_args.each do |e|
368
440
  #Force block arg(s) to be local
@@ -663,7 +735,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
663
735
  end
664
736
  end
665
737
  else
666
- new_value = process s(:call, s(:call, target_var, :[], index), exp[3], value)
738
+ new_value = process s(:call, s(:call, target_var, :[], index), exp[3], value).line(exp.line)
667
739
 
668
740
  env[match] = new_value
669
741
  end
@@ -941,7 +1013,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
941
1013
  args = exp.args
942
1014
  exp.pop # remove last arg
943
1015
  if args.length > 1
944
- exp.arglist = args[1..-1]
1016
+ exp.arglist = args.sexp_body
945
1017
  end
946
1018
  end
947
1019
 
@@ -986,8 +1058,8 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
986
1058
  method_name = call.method
987
1059
 
988
1060
  #Look for helper methods and see if we can get a return value
989
- if found_method = find_method(method_name, @current_class)
990
- helper = found_method[:method]
1061
+ if found_method = tracker.find_method(method_name, @current_class)
1062
+ helper = found_method.src
991
1063
 
992
1064
  if sexp? helper
993
1065
  value = process_helper_method helper, call.args