brakeman 4.10.1 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +25 -0
  3. data/README.md +1 -1
  4. data/bundle/load.rb +2 -2
  5. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/History.rdoc +6 -0
  6. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/Manifest.txt +0 -0
  7. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/README.rdoc +0 -0
  8. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/compare/normalize.rb +0 -0
  9. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/debugging.md +0 -0
  10. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/rp_extensions.rb +0 -0
  11. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/rp_stringscanner.rb +0 -0
  12. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby20_parser.rb +0 -0
  13. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby20_parser.y +0 -0
  14. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby21_parser.rb +0 -0
  15. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby21_parser.y +0 -0
  16. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby22_parser.rb +0 -0
  17. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby22_parser.y +0 -0
  18. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby23_parser.rb +0 -0
  19. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby23_parser.y +0 -0
  20. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby24_parser.rb +0 -0
  21. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby24_parser.y +0 -0
  22. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby25_parser.rb +0 -0
  23. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby25_parser.y +0 -0
  24. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby26_parser.rb +0 -0
  25. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby26_parser.y +0 -0
  26. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby27_parser.rb +0 -0
  27. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby27_parser.y +0 -0
  28. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby_lexer.rb +0 -0
  29. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby_lexer.rex +0 -0
  30. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby_lexer.rex.rb +0 -0
  31. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby_parser.rb +0 -0
  32. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby_parser.yy +0 -0
  33. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/lib/ruby_parser_extras.rb +1 -1
  34. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/tools/munge.rb +0 -0
  35. data/bundle/ruby/2.7.0/gems/{ruby_parser-3.15.0 → ruby_parser-3.15.1}/tools/ripper.rb +0 -0
  36. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/History.rdoc +6 -0
  37. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/Manifest.txt +0 -0
  38. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/README.rdoc +0 -0
  39. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/lib/composite_sexp_processor.rb +0 -0
  40. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/lib/pt_testcase.rb +0 -0
  41. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/lib/sexp.rb +0 -0
  42. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/lib/sexp_matcher.rb +0 -0
  43. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/lib/sexp_processor.rb +1 -1
  44. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/lib/strict_sexp.rb +0 -0
  45. data/bundle/ruby/2.7.0/gems/{sexp_processor-4.15.1 → sexp_processor-4.15.2}/lib/unique.rb +0 -0
  46. data/lib/brakeman.rb +6 -0
  47. data/lib/brakeman/app_tree.rb +36 -3
  48. data/lib/brakeman/checks/base_check.rb +7 -1
  49. data/lib/brakeman/checks/check_execute.rb +1 -0
  50. data/lib/brakeman/checks/check_sql.rb +1 -1
  51. data/lib/brakeman/checks/check_unsafe_reflection_methods.rb +68 -0
  52. data/lib/brakeman/checks/check_verb_confusion.rb +75 -0
  53. data/lib/brakeman/file_parser.rb +19 -18
  54. data/lib/brakeman/options.rb +5 -1
  55. data/lib/brakeman/parsers/template_parser.rb +2 -3
  56. data/lib/brakeman/processors/alias_processor.rb +18 -2
  57. data/lib/brakeman/processors/lib/file_type_detector.rb +64 -0
  58. data/lib/brakeman/processors/lib/rails3_config_processor.rb +16 -16
  59. data/lib/brakeman/report.rb +8 -0
  60. data/lib/brakeman/report/report_base.rb +0 -2
  61. data/lib/brakeman/report/report_csv.rb +37 -60
  62. data/lib/brakeman/report/report_junit.rb +2 -2
  63. data/lib/brakeman/report/report_sarif.rb +1 -1
  64. data/lib/brakeman/report/report_sonar.rb +38 -0
  65. data/lib/brakeman/report/report_tabs.rb +1 -1
  66. data/lib/brakeman/report/report_text.rb +1 -1
  67. data/lib/brakeman/rescanner.rb +7 -5
  68. data/lib/brakeman/scanner.rb +44 -18
  69. data/lib/brakeman/tracker.rb +6 -0
  70. data/lib/brakeman/tracker/config.rb +73 -0
  71. data/lib/brakeman/util.rb +7 -2
  72. data/lib/brakeman/version.rb +1 -1
  73. data/lib/brakeman/warning.rb +10 -2
  74. data/lib/brakeman/warning_codes.rb +2 -0
  75. metadata +48 -44
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1266c840ed2a8f9b6e44686cba353eb6f75eb8d4ec87c7bbdcc56d81785b9227
4
- data.tar.gz: a0ed358121968434f3289b25685970d338d72f1d1f97b0c27103a81a9792cb16
3
+ metadata.gz: 1d660b98db2252a6aa69d39bb56c6950aa7d9713f10831807d6ab837df54657d
4
+ data.tar.gz: 6999959ba9f8380f36c1d999e04b0d79e48ea9536fd9820485c4960bce769d60
5
5
  SHA512:
6
- metadata.gz: 22f064e0f38f304c3d9a18e0c7d36999b7161f9e33ff5c5cd4bca669d19b331e0f92651eb238faf1fd58de66c14da166d7de89353913d806d970f77eb87fa992
7
- data.tar.gz: 4345e389eb3f592139f32cf70b8d618fcb8695cee9f4a8398fdaa636ac5e9be7b2b0ebe6667810f5cd0667f33898effcd9fbf8beac36f48883da73b68fa7c76f
6
+ metadata.gz: b6738f567478a47fd36de992706968c1c42a237dd97d4527434a60fa9ddea5b7a7acb54d8b72e6bc282fd1805126953a358e399a19dab4c0c5e7fd92b4a857ed
7
+ data.tar.gz: 43f16437835dabb65a7b73981779460e7648e1fa2ba772320132e7500af55c8861effda46f3b181310bdd753dbf1c59af12b3ecdfed5844505e2cf5cbff866fa
data/CHANGES.md CHANGED
@@ -1,3 +1,18 @@
1
+ # 5.0.0 - 2021-01-26
2
+
3
+ * Ignore `uuid` as a safe attribute
4
+ * Collapse `__send__` calls
5
+ * Ignore `Tempfile#path` in shell commands
6
+ * Ignore development environment
7
+ * Revamp CSV report to a CSV list of warnings
8
+ * Set Rails configuration defaults based on `load_defaults` version
9
+ * Add check for (more) unsafe method reflection
10
+ * Suggest using `--force` if no Rails application is detected
11
+ * Add Sonarqube report format (Adam England)
12
+ * Add check for potential HTTP verb confusion
13
+ * Add `--[no-]skip-vendor` option
14
+ * Scan (almost) all Ruby files in project
15
+
1
16
  # 4.10.1 - 2020-12-24
2
17
 
3
18
  * Declare REXML as a dependency (Ruby 3.0 compatibility)
@@ -6,6 +21,16 @@
6
21
  * Ensure RubyParser is passed file path as a String
7
22
  * Support new Haml 5.2.0 escaping method
8
23
 
24
+ # 5.0.0.pre1 - 2020-11-17
25
+
26
+ * Add check for (more) unsafe method reflection
27
+ * Suggest using `--force` if no Rails application is detected
28
+ * Add Sonarqube report format (Adam England)
29
+ * Add check for potential HTTP verb confusion
30
+ * Add `--[no-]skip-vendor` option
31
+ * Scan (almost) all Ruby files in project
32
+ * Add support for Haml 5.2.0
33
+
9
34
  # 4.10.0 - 2020-09-28
10
35
 
11
36
  * Add SARIF report format (Steve Winton)
data/README.md CHANGED
@@ -76,7 +76,7 @@ To specify an output file for the results:
76
76
 
77
77
  brakeman -o output_file
78
78
 
79
- The output format is determined by the file extension or by using the `-f` option. Current options are: `text`, `html`, `tabs`, `json`, `junit`, `markdown`, `csv`, and `codeclimate`.
79
+ The output format is determined by the file extension or by using the `-f` option. Current options are: `text`, `html`, `tabs`, `json`, `junit`, `markdown`, `csv`, `codeclimate`, and `sonar`.
80
80
 
81
81
  Multiple output files can be specified:
82
82
 
data/bundle/load.rb CHANGED
@@ -1,10 +1,9 @@
1
1
  path = File.expand_path('../..', __FILE__)
2
- $:.unshift "#{path}/bundle/ruby/2.7.0/gems/ruby_parser-3.15.0/lib"
3
2
  $:.unshift "#{path}/bundle/ruby/2.7.0/gems/temple-0.8.2/lib"
4
3
  $:.unshift "#{path}/bundle/ruby/2.7.0/gems/unicode-display_width-1.7.0/lib"
5
- $:.unshift "#{path}/bundle/ruby/2.7.0/gems/sexp_processor-4.15.1/lib"
6
4
  $:.unshift "#{path}/bundle/ruby/2.7.0/gems/tilt-2.0.10/lib"
7
5
  $:.unshift "#{path}/bundle/ruby/2.7.0/gems/slim-4.1.0/lib"
6
+ $:.unshift "#{path}/bundle/ruby/2.7.0/gems/sexp_processor-4.15.2/lib"
8
7
  $:.unshift "#{path}/bundle/ruby/2.7.0/gems/highline-2.0.3/lib"
9
8
  $:.unshift "#{path}/bundle/ruby/2.7.0/gems/ruby2ruby-2.4.4/lib"
10
9
  $:.unshift "#{path}/bundle/ruby/2.7.0/gems/terminal-table-1.8.0/lib"
@@ -12,4 +11,5 @@ $:.unshift "#{path}/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib"
12
11
  $:.unshift "#{path}/bundle/ruby/2.7.0/gems/ruby_parser-legacy-1.0.0/lib"
13
12
  $:.unshift "#{path}/bundle/ruby/2.7.0/gems/erubis-2.7.0/lib"
14
13
  $:.unshift "#{path}/bundle/ruby/2.7.0/gems/haml-5.2.1/lib"
14
+ $:.unshift "#{path}/bundle/ruby/2.7.0/gems/ruby_parser-3.15.1/lib"
15
15
  $:.unshift "#{path}/bundle/ruby/2.7.0/gems/safe_yaml-1.0.5/lib"
@@ -1,3 +1,9 @@
1
+ === 3.15.1 / 2021-01-10
2
+
3
+ * 1 bug fix:
4
+
5
+ * Bumped ruby version to include < 4 (trunk).
6
+
1
7
  === 3.15.0 / 2020-08-31
2
8
 
3
9
  * 1 major enhancement:
@@ -29,7 +29,7 @@ class Sexp
29
29
  end
30
30
 
31
31
  module RubyParserStuff
32
- VERSION = "3.15.0"
32
+ VERSION = "3.15.1"
33
33
 
34
34
  attr_accessor :lexer, :in_def, :in_single, :file
35
35
  attr_accessor :in_kwarg
@@ -1,3 +1,9 @@
1
+ === 4.15.2 / 2021-01-10
2
+
3
+ * 1 bug fix:
4
+
5
+ * Bumped ruby version to include < 4 (trunk).
6
+
1
7
  === 4.15.1 / 2020-08-31
2
8
 
3
9
  * 1 bug fix:
@@ -34,7 +34,7 @@ require "sexp"
34
34
  class SexpProcessor
35
35
 
36
36
  # duh
37
- VERSION = "4.15.1"
37
+ VERSION = "4.15.2"
38
38
 
39
39
  ##
40
40
  # Automatically shifts off the Sexp type before handing the
data/lib/brakeman.rb CHANGED
@@ -66,6 +66,7 @@ module Brakeman
66
66
  # * :run_checks - array of checks to run (run all if not specified)
67
67
  # * :safe_methods - array of methods to consider safe
68
68
  # * :skip_libs - do not process lib/ directory (default: false)
69
+ # * :skip_vendor - do not process vendor/ directory (default: true)
69
70
  # * :skip_checks - checks not to run (run all if not specified)
70
71
  # * :absolute_paths - show absolute path of each file (default: false)
71
72
  # * :summary_only - only output summary section of report for plain/table (:summary_only, :no_summary, true)
@@ -191,6 +192,7 @@ module Brakeman
191
192
  :report_progress => true,
192
193
  :safe_methods => Set.new,
193
194
  :skip_checks => Set.new,
195
+ :skip_vendor => true,
194
196
  }
195
197
  end
196
198
 
@@ -239,6 +241,8 @@ module Brakeman
239
241
  [:to_junit]
240
242
  when :sarif, :to_sarif
241
243
  [:to_sarif]
244
+ when :sonar, :to_sonar
245
+ [:to_sonar]
242
246
  else
243
247
  [:to_text]
244
248
  end
@@ -270,6 +274,8 @@ module Brakeman
270
274
  :to_junit
271
275
  when /\.sarif$/i
272
276
  :to_sarif
277
+ when /\.sonar$/i
278
+ :to_sonar
273
279
  else
274
280
  :to_text
275
281
  end
@@ -21,6 +21,7 @@ module Brakeman
21
21
  end
22
22
  init_options[:additional_libs_path] = options[:additional_libs_path]
23
23
  init_options[:engine_paths] = options[:engine_paths]
24
+ init_options[:skip_vendor] = options[:skip_vendor]
24
25
  new(root, init_options)
25
26
  end
26
27
 
@@ -62,6 +63,7 @@ module Brakeman
62
63
  @engine_paths = init_options[:engine_paths] || []
63
64
  @absolute_engine_paths = @engine_paths.select { |path| path.start_with?(File::SEPARATOR) }
64
65
  @relative_engine_paths = @engine_paths - @absolute_engine_paths
66
+ @skip_vendor = init_options[:skip_vendor]
65
67
  @gemspec = nil
66
68
  @root_search_pattern = nil
67
69
  end
@@ -96,6 +98,10 @@ module Brakeman
96
98
  end
97
99
  end
98
100
 
101
+ def ruby_file_paths
102
+ find_paths(".").uniq
103
+ end
104
+
99
105
  def initializer_paths
100
106
  @initializer_paths ||= prioritize_concerns(find_paths("config/initializers"))
101
107
  end
@@ -109,8 +115,8 @@ module Brakeman
109
115
  end
110
116
 
111
117
  def template_paths
112
- @template_paths ||= find_paths("app/**/views", "*.{#{VIEW_EXTENSIONS}}") +
113
- find_paths("app/**/views", "*.{erb,haml,slim}").reject { |path| File.basename(path).count(".") > 1 }
118
+ @template_paths ||= find_paths(".", "*.{#{VIEW_EXTENSIONS}}") +
119
+ find_paths("**", "*.{erb,haml,slim}").reject { |path| File.basename(path).count(".") > 1 }
114
120
  end
115
121
 
116
122
  def layout_exists?(name)
@@ -163,7 +169,8 @@ module Brakeman
163
169
  def select_files(paths)
164
170
  paths = select_only_files(paths)
165
171
  paths = reject_skipped_files(paths)
166
- convert_to_file_paths(paths)
172
+ paths = convert_to_file_paths(paths)
173
+ reject_global_excludes(paths)
167
174
  end
168
175
 
169
176
  def select_only_files(paths)
@@ -182,6 +189,32 @@ module Brakeman
182
189
  end
183
190
  end
184
191
 
192
+ EXCLUDED_PATHS = %w[
193
+ /generators/
194
+ lib/tasks/
195
+ lib/templates/
196
+ db/
197
+ spec/
198
+ test/
199
+ tmp/
200
+ public/
201
+ log/
202
+ ]
203
+
204
+ def reject_global_excludes(paths)
205
+ paths.reject do |path|
206
+ relative_path = path.relative
207
+
208
+ if @skip_vendor and relative_path.include? 'vendor/'
209
+ true
210
+ else
211
+ EXCLUDED_PATHS.any? do |excluded|
212
+ relative_path.include? excluded
213
+ end
214
+ end
215
+ end
216
+ end
217
+
185
218
  def match_path files, path
186
219
  absolute_path = Pathname.new(path)
187
220
  # relative root never has a leading separator. But, we use a leading
@@ -40,7 +40,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
40
40
  @mass_assign_disabled = nil
41
41
  @has_user_input = nil
42
42
  @in_array = false
43
- @safe_input_attributes = Set[:to_i, :to_f, :arel_table, :id]
43
+ @safe_input_attributes = Set[:to_i, :to_f, :arel_table, :id, :uuid]
44
44
  @comparison_ops = Set[:==, :!=, :>, :<, :>=, :<=]
45
45
  end
46
46
 
@@ -151,6 +151,12 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
151
151
  method[-1] == "?"
152
152
  end
153
153
 
154
+ TEMP_FILE_PATH = s(:call, s(:call, s(:const, :Tempfile), :new), :path).freeze
155
+
156
+ def temp_file_path? exp
157
+ exp == TEMP_FILE_PATH
158
+ end
159
+
154
160
  #Report a warning
155
161
  def warn options
156
162
  extra_opts = { :check => self.class.to_s }
@@ -204,6 +204,7 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
204
204
  next if node_type? e, :lit, :str
205
205
  next if SAFE_VALUES.include? e
206
206
  next if shell_escape? e
207
+ next if temp_file_path? e
207
208
 
208
209
  if node_type? e, :if
209
210
  # If we're in a conditional, evaluate the `then` and `else` clauses to
@@ -576,7 +576,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
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
@@ -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