brakeman 4.9.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (183) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +44 -0
  3. data/README.md +1 -1
  4. data/bundle/load.rb +4 -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/rexml-3.2.4/Gemfile +6 -0
  46. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/LICENSE.txt +22 -0
  47. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/NEWS.md +141 -0
  48. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/README.md +60 -0
  49. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/attlistdecl.rb +63 -0
  50. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/attribute.rb +205 -0
  51. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/cdata.rb +68 -0
  52. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/child.rb +97 -0
  53. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/comment.rb +80 -0
  54. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/doctype.rb +287 -0
  55. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/document.rb +291 -0
  56. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/attlistdecl.rb +11 -0
  57. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/dtd.rb +47 -0
  58. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/elementdecl.rb +18 -0
  59. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/entitydecl.rb +57 -0
  60. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/notationdecl.rb +40 -0
  61. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/element.rb +1269 -0
  62. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/encoding.rb +51 -0
  63. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/entity.rb +171 -0
  64. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/formatters/default.rb +116 -0
  65. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/formatters/pretty.rb +142 -0
  66. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/formatters/transitive.rb +58 -0
  67. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/functions.rb +447 -0
  68. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/instruction.rb +79 -0
  69. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/light/node.rb +196 -0
  70. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/namespace.rb +59 -0
  71. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/node.rb +76 -0
  72. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/output.rb +30 -0
  73. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parent.rb +166 -0
  74. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parseexception.rb +52 -0
  75. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/baseparser.rb +594 -0
  76. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/lightparser.rb +59 -0
  77. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/pullparser.rb +197 -0
  78. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/sax2parser.rb +273 -0
  79. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/streamparser.rb +61 -0
  80. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/treeparser.rb +101 -0
  81. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/ultralightparser.rb +57 -0
  82. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/xpathparser.rb +675 -0
  83. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/quickpath.rb +266 -0
  84. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/rexml.rb +32 -0
  85. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/sax2listener.rb +98 -0
  86. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/security.rb +28 -0
  87. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/source.rb +298 -0
  88. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/streamlistener.rb +93 -0
  89. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/text.rb +424 -0
  90. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/undefinednamespaceexception.rb +9 -0
  91. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/validation/relaxng.rb +539 -0
  92. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/validation/validation.rb +144 -0
  93. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/validation/validationexception.rb +10 -0
  94. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/xmldecl.rb +130 -0
  95. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/xmltokens.rb +85 -0
  96. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/xpath.rb +81 -0
  97. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/xpath_parser.rb +968 -0
  98. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/rexml.gemspec +84 -0
  99. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/History.rdoc +41 -0
  100. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/Manifest.txt +2 -0
  101. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/README.rdoc +0 -0
  102. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/compare/normalize.rb +43 -3
  103. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.1/debugging.md +57 -0
  104. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/lib/rp_extensions.rb +0 -0
  105. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/lib/rp_stringscanner.rb +0 -0
  106. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.1/lib/ruby20_parser.rb +7062 -0
  107. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/lib/ruby20_parser.y +91 -58
  108. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/lib/ruby21_parser.rb +2603 -2576
  109. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/lib/ruby21_parser.y +91 -58
  110. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.1/lib/ruby22_parser.rb +7160 -0
  111. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/lib/ruby22_parser.y +91 -58
  112. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.1/lib/ruby23_parser.rb +7175 -0
  113. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/lib/ruby23_parser.y +91 -58
  114. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.1/lib/ruby24_parser.rb +7204 -0
  115. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/lib/ruby24_parser.y +91 -58
  116. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2/lib/ruby23_parser.rb → ruby_parser-3.15.1/lib/ruby25_parser.rb} +2867 -2826
  117. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/lib/ruby25_parser.y +91 -58
  118. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2/lib/ruby25_parser.rb → ruby_parser-3.15.1/lib/ruby26_parser.rb} +2432 -2383
  119. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/lib/ruby26_parser.y +91 -58
  120. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2/lib/ruby24_parser.rb → ruby_parser-3.15.1/lib/ruby27_parser.rb} +2432 -2383
  121. data/bundle/ruby/2.7.0/gems/ruby_parser-3.15.1/lib/ruby27_parser.y +2657 -0
  122. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/lib/ruby_lexer.rb +72 -40
  123. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/lib/ruby_lexer.rex +5 -6
  124. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/lib/ruby_lexer.rex.rb +6 -8
  125. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/lib/ruby_parser.rb +2 -0
  126. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/lib/ruby_parser.yy +93 -58
  127. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/lib/ruby_parser_extras.rb +49 -16
  128. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/tools/munge.rb +9 -4
  129. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.14.2 → ruby_parser-3.15.1}/tools/ripper.rb +0 -0
  130. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.0 → sexp_processor-4.15.2}/History.rdoc +12 -0
  131. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.0 → sexp_processor-4.15.2}/Manifest.txt +0 -0
  132. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.0 → sexp_processor-4.15.2}/README.rdoc +0 -0
  133. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.0 → sexp_processor-4.15.2}/lib/composite_sexp_processor.rb +0 -0
  134. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.0 → sexp_processor-4.15.2}/lib/pt_testcase.rb +2 -2
  135. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.0 → sexp_processor-4.15.2}/lib/sexp.rb +0 -0
  136. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.0 → sexp_processor-4.15.2}/lib/sexp_matcher.rb +0 -0
  137. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.0 → sexp_processor-4.15.2}/lib/sexp_processor.rb +1 -1
  138. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.0 → sexp_processor-4.15.2}/lib/strict_sexp.rb +0 -0
  139. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.0 → sexp_processor-4.15.2}/lib/unique.rb +0 -0
  140. data/lib/brakeman.rb +10 -0
  141. data/lib/brakeman/app_tree.rb +36 -3
  142. data/lib/brakeman/checks/base_check.rb +7 -1
  143. data/lib/brakeman/checks/check_execute.rb +2 -1
  144. data/lib/brakeman/checks/check_model_attributes.rb +1 -1
  145. data/lib/brakeman/checks/check_regex_dos.rb +1 -1
  146. data/lib/brakeman/checks/check_sql.rb +2 -2
  147. data/lib/brakeman/checks/check_unsafe_reflection_methods.rb +68 -0
  148. data/lib/brakeman/checks/check_verb_confusion.rb +75 -0
  149. data/lib/brakeman/file_parser.rb +24 -18
  150. data/lib/brakeman/options.rb +5 -1
  151. data/lib/brakeman/parsers/template_parser.rb +2 -3
  152. data/lib/brakeman/processors/alias_processor.rb +20 -4
  153. data/lib/brakeman/processors/controller_processor.rb +1 -1
  154. data/lib/brakeman/processors/haml_template_processor.rb +8 -1
  155. data/lib/brakeman/processors/lib/call_conversion_helper.rb +1 -1
  156. data/lib/brakeman/processors/lib/file_type_detector.rb +64 -0
  157. data/lib/brakeman/processors/lib/rails3_config_processor.rb +16 -16
  158. data/lib/brakeman/processors/output_processor.rb +1 -1
  159. data/lib/brakeman/processors/template_alias_processor.rb +5 -0
  160. data/lib/brakeman/report.rb +15 -0
  161. data/lib/brakeman/report/report_base.rb +0 -2
  162. data/lib/brakeman/report/report_csv.rb +37 -60
  163. data/lib/brakeman/report/report_junit.rb +2 -2
  164. data/lib/brakeman/report/report_sarif.rb +114 -0
  165. data/lib/brakeman/report/report_sonar.rb +38 -0
  166. data/lib/brakeman/report/report_tabs.rb +1 -1
  167. data/lib/brakeman/report/report_text.rb +1 -1
  168. data/lib/brakeman/rescanner.rb +7 -5
  169. data/lib/brakeman/scanner.rb +44 -18
  170. data/lib/brakeman/tracker.rb +6 -0
  171. data/lib/brakeman/tracker/config.rb +76 -1
  172. data/lib/brakeman/tracker/controller.rb +1 -1
  173. data/lib/brakeman/util.rb +9 -4
  174. data/lib/brakeman/version.rb +1 -1
  175. data/lib/brakeman/warning.rb +10 -2
  176. data/lib/brakeman/warning_codes.rb +2 -0
  177. data/lib/ruby_parser/bm_sexp.rb +9 -9
  178. metadata +143 -82
  179. data/bundle/ruby/2.7.0/gems/haml-5.1.2/lib/haml/escapable.rb +0 -50
  180. data/bundle/ruby/2.7.0/gems/ruby_parser-3.14.2/debugging.md +0 -18
  181. data/bundle/ruby/2.7.0/gems/ruby_parser-3.14.2/lib/ruby20_parser.rb +0 -7042
  182. data/bundle/ruby/2.7.0/gems/ruby_parser-3.14.2/lib/ruby22_parser.rb +0 -7146
  183. data/bundle/ruby/2.7.0/gems/ruby_parser-3.14.2/lib/ruby26_parser.rb +0 -7195
@@ -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
@@ -3,50 +3,56 @@ module Brakeman
3
3
 
4
4
  # This class handles reading and parsing files.
5
5
  class FileParser
6
- attr_reader :file_list
6
+ attr_reader :file_list, :errors
7
7
 
8
- def initialize tracker
9
- @tracker = tracker
10
- @timeout = @tracker.options[:parser_timeout]
11
- @app_tree = @tracker.app_tree
12
- @file_list = {}
8
+ def initialize app_tree, timeout
9
+ @app_tree = app_tree
10
+ @timeout = timeout
11
+ @file_list = []
12
+ @errors = []
13
13
  end
14
14
 
15
- def parse_files list, type
16
- read_files list, type do |path, contents|
15
+ def parse_files list
16
+ read_files list do |path, contents|
17
17
  if ast = parse_ruby(contents, path.relative)
18
18
  ASTFile.new(path, ast)
19
19
  end
20
20
  end
21
21
  end
22
22
 
23
- def read_files list, type
24
- @file_list[type] ||= []
25
-
23
+ def read_files list
26
24
  list.each do |path|
27
25
  file = @app_tree.file_path(path)
28
26
 
29
27
  result = yield file, file.read
28
+
30
29
  if result
31
- @file_list[type] << result
30
+ @file_list << result
32
31
  end
33
32
  end
34
33
  end
35
34
 
35
+ # _path_ can be a string or a Brakeman::FilePath
36
36
  def parse_ruby input, path
37
+ if path.is_a? Brakeman::FilePath
38
+ path = path.relative
39
+ end
40
+
37
41
  begin
38
42
  Brakeman.debug "Parsing #{path}"
39
43
  RubyParser.new.parse input, path, @timeout
40
44
  rescue Racc::ParseError => e
41
- @tracker.error e, "Could not parse #{path}"
42
- nil
45
+ error e.exception(e.message + "\nCould not parse #{path}")
43
46
  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
47
+ error Exception.new("Parsing #{path} took too long (> #{@timeout} seconds). Try increasing the limit with --parser-timeout")
46
48
  rescue => e
47
- @tracker.error e.exception(e.message + "\nWhile processing #{path}"), e.backtrace
48
- nil
49
+ error e.exception(e.message + "\nWhile processing #{path}")
49
50
  end
50
51
  end
52
+
53
+ def error exception
54
+ @errors << exception
55
+ nil
56
+ end
51
57
  end
52
58
  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],
236
+ [:pdf, :text, :html, :csv, :tabs, :json, :markdown, :codeclimate, :cc, :plain, :table, :junit, :sarif, :sonar],
233
237
  "Specify output formats. Default is text" do |type|
234
238
 
235
239
  type = "s" if type == :text
@@ -9,7 +9,6 @@ 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] ||= []
13
12
  end
14
13
 
15
14
  def parse_template path, text
@@ -33,7 +32,7 @@ module Brakeman
33
32
  end
34
33
 
35
34
  if src and ast = @file_parser.parse_ruby(src, path)
36
- @file_parser.file_list[:templates] << TemplateFile.new(path, ast, name, type)
35
+ @file_parser.file_list << TemplateFile.new(path, ast, name, type)
37
36
  end
38
37
  rescue Racc::ParseError => e
39
38
  tracker.error e, "Could not parse #{path}"
@@ -97,7 +96,7 @@ module Brakeman
97
96
  end
98
97
 
99
98
  def self.parse_inline_erb tracker, text
100
- fp = Brakeman::FileParser.new(tracker)
99
+ fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout])
101
100
  tp = self.new(tracker, fp)
102
101
  src = tp.parse_erb '_inline_', text
103
102
  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
@@ -186,7 +187,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
186
187
  method = exp.method
187
188
  first_arg = exp.first_arg
188
189
 
189
- if method == :send or method == :try
190
+ if method == :send or method == :__send__ or method == :try
190
191
  collapse_send_call exp, first_arg
191
192
  end
192
193
 
@@ -197,7 +198,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
197
198
  return Sexp.new(:array, *exp.args)
198
199
  elsif target == HASH_CONST and method == :new and first_arg.nil? and !node_type?(@exp_context.last, :iter)
199
200
  return Sexp.new(:hash)
200
- elsif exp == RAILS_TEST
201
+ elsif exp == RAILS_TEST or exp == RAILS_DEV
201
202
  return Sexp.new(:false)
202
203
  end
203
204
 
@@ -236,7 +237,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
236
237
  env[target_var] = target
237
238
  return target
238
239
  elsif string? target and string_interp? first_arg
239
- exp = Sexp.new(:dstr, target.value + first_arg[1]).concat(first_arg[2..-1])
240
+ exp = Sexp.new(:dstr, target.value + first_arg[1]).concat(first_arg.sexp_body(2))
240
241
  env[target_var] = exp
241
242
  elsif string? first_arg and string_interp? target
242
243
  if string? target.last
@@ -346,6 +347,18 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
346
347
  end
347
348
  end
348
349
 
350
+ TEMP_FILE_CLASS = s(:const, :Tempfile)
351
+
352
+ def temp_file_open? exp
353
+ call? exp and
354
+ exp.target == TEMP_FILE_CLASS and
355
+ exp.method == :open
356
+ end
357
+
358
+ def temp_file_new line
359
+ s(:call, TEMP_FILE_CLASS, :new).line(line)
360
+ end
361
+
349
362
  def process_iter exp
350
363
  @exp_context.push exp
351
364
  exp[1] = process exp.block_call
@@ -363,6 +376,9 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
363
376
  # Iterating over an array of all literal values
364
377
  local = Sexp.new(:lvar, block_args.last)
365
378
  env.current[local] = safe_literal(exp.line)
379
+ elsif temp_file_open? call
380
+ local = Sexp.new(:lvar, block_args.last)
381
+ env.current[local] = temp_file_new(exp.line)
366
382
  else
367
383
  block_args.each do |e|
368
384
  #Force block arg(s) to be local
@@ -941,7 +957,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
941
957
  args = exp.args
942
958
  exp.pop # remove last arg
943
959
  if args.length > 1
944
- exp.arglist = args[1..-1]
960
+ exp.arglist = args.sexp_body
945
961
  end
946
962
  end
947
963
 
@@ -202,7 +202,7 @@ class Brakeman::ControllerProcessor < Brakeman::BaseProcessor
202
202
  end
203
203
 
204
204
  if node_type? exp.block, :block
205
- block_inner = exp.block[1..-1]
205
+ block_inner = exp.block.sexp_body
206
206
  else
207
207
  block_inner = [exp.block]
208
208
  end
@@ -76,6 +76,13 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
76
76
  end
77
77
  end
78
78
 
79
+ ESCAPE_METHODS = [
80
+ :html_escape,
81
+ :html_escape_without_haml_xss,
82
+ :escape_once,
83
+ :escape_once_without_haml_xss
84
+ ]
85
+
79
86
  def get_pushed_value exp, default = :output
80
87
  return exp unless sexp? exp
81
88
 
@@ -105,7 +112,7 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
105
112
  when :call
106
113
  if exp.method == :to_s or exp.method == :strip
107
114
  get_pushed_value(exp.target, default)
108
- elsif haml_helpers? exp.target and exp.method == :html_escape
115
+ elsif haml_helpers? exp.target and ESCAPE_METHODS.include? exp.method
109
116
  get_pushed_value(exp.first_arg, :escaped_output)
110
117
  elsif @javascript and (exp.method == :j or exp.method == :escape_javascript) # TODO: Remove - this is not safe
111
118
  get_pushed_value(exp.first_arg, :escaped_output)
@@ -10,7 +10,7 @@ module Brakeman
10
10
  def join_arrays lhs, rhs, original_exp = nil
11
11
  if array? lhs and array? rhs
12
12
  result = Sexp.new(:array)
13
- result.line(lhs.line || rhs.line)
13
+ result.line(lhs.line || rhs.line || 1)
14
14
  result.concat lhs[1..-1]
15
15
  result.concat rhs[1..-1]
16
16
  result
@@ -0,0 +1,64 @@
1
+ module Brakeman
2
+ class FileTypeDetector < BaseProcessor
3
+ def initialize
4
+ super(nil)
5
+ reset
6
+ end
7
+
8
+ def detect_type(file)
9
+ reset
10
+ process(file.ast)
11
+
12
+ if @file_type.nil?
13
+ @file_type = guess_from_path(file.path.relative)
14
+ end
15
+
16
+ @file_type || :libs
17
+ end
18
+
19
+ MODEL_CLASSES = [
20
+ :'ActiveRecord::Base',
21
+ :ApplicationRecord
22
+ ]
23
+
24
+ def process_class exp
25
+ name = class_name(exp.class_name)
26
+ parent = class_name(exp.parent_name)
27
+
28
+ if name.match(/Controller$/)
29
+ @file_type = :controllers
30
+ return exp
31
+ elsif MODEL_CLASSES.include? parent
32
+ @file_type = :models
33
+ return exp
34
+ end
35
+
36
+ super
37
+ end
38
+
39
+ def guess_from_path path
40
+ case
41
+ when path.include?('app/models')
42
+ :models
43
+ when path.include?('app/controllers')
44
+ :controllers
45
+ when path.include?('config/initializers')
46
+ :initializers
47
+ when path.include?('lib/')
48
+ :libs
49
+ when path.match?(%r{config/environments/(?!production\.rb)$})
50
+ :skip
51
+ when path.match?(%r{environments/production\.rb$})
52
+ :skip
53
+ when path.match?(%r{application\.rb$})
54
+ :skip
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def reset
61
+ @file_type = nil
62
+ end
63
+ end
64
+ end
@@ -57,6 +57,20 @@ class Brakeman::Rails3ConfigProcessor < Brakeman::BasicProcessor
57
57
  exp
58
58
  end
59
59
 
60
+ #Look for configuration settings that
61
+ #are just a call like
62
+ #
63
+ # config.load_defaults 5.2
64
+ def process_call exp
65
+ return exp unless @inside_config
66
+
67
+ if exp.target == RAILS_CONFIG and exp.first_arg
68
+ @tracker.config.rails[exp.method] = exp.first_arg
69
+ end
70
+
71
+ exp
72
+ end
73
+
60
74
  #Look for configuration settings
61
75
  def process_attrasgn exp
62
76
  return exp unless @inside_config
@@ -71,22 +85,8 @@ class Brakeman::Rails3ConfigProcessor < Brakeman::BasicProcessor
71
85
  @tracker.config.rails[attribute] = exp.first_arg
72
86
  end
73
87
  elsif include_rails_config? exp
74
- options = get_rails_config exp
75
- level = @tracker.config.rails
76
- options[0..-2].each do |o|
77
- level[o] ||= {}
78
-
79
- option = level[o]
80
-
81
- if not option.is_a? Hash
82
- Brakeman.debug "[Notice] Skipping config setting: #{options.map(&:to_s).join(".")}"
83
- return exp
84
- end
85
-
86
- level = level[o]
87
- end
88
-
89
- level[options.last] = exp.first_arg
88
+ options_path = get_rails_config exp
89
+ @tracker.config.set_rails_config(exp.first_arg, *options_path)
90
90
  end
91
91
 
92
92
  exp