brakeman-min 4.8.1 → 4.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +39 -0
  3. data/README.md +5 -3
  4. data/lib/brakeman.rb +20 -0
  5. data/lib/brakeman/checks/base_check.rb +1 -1
  6. data/lib/brakeman/checks/check_basic_auth.rb +2 -0
  7. data/lib/brakeman/checks/check_csrf_token_forgery_cve.rb +28 -0
  8. data/lib/brakeman/checks/check_deserialize.rb +21 -1
  9. data/lib/brakeman/checks/check_execute.rb +1 -1
  10. data/lib/brakeman/checks/check_json_entity_escape.rb +38 -0
  11. data/lib/brakeman/checks/check_mass_assignment.rb +19 -4
  12. data/lib/brakeman/checks/check_model_attr_accessible.rb +1 -1
  13. data/lib/brakeman/checks/check_model_attributes.rb +1 -1
  14. data/lib/brakeman/checks/check_page_caching_cve.rb +37 -0
  15. data/lib/brakeman/checks/check_permit_attributes.rb +1 -1
  16. data/lib/brakeman/checks/check_regex_dos.rb +1 -1
  17. data/lib/brakeman/checks/check_skip_before_filter.rb +4 -4
  18. data/lib/brakeman/checks/check_sql.rb +1 -1
  19. data/lib/brakeman/checks/check_template_injection.rb +32 -0
  20. data/lib/brakeman/commandline.rb +25 -1
  21. data/lib/brakeman/file_parser.rb +5 -0
  22. data/lib/brakeman/options.rb +21 -1
  23. data/lib/brakeman/processors/alias_processor.rb +4 -5
  24. data/lib/brakeman/processors/controller_processor.rb +1 -1
  25. data/lib/brakeman/processors/haml_template_processor.rb +8 -1
  26. data/lib/brakeman/processors/lib/call_conversion_helper.rb +1 -1
  27. data/lib/brakeman/processors/lib/find_all_calls.rb +27 -12
  28. data/lib/brakeman/processors/output_processor.rb +1 -1
  29. data/lib/brakeman/processors/template_alias_processor.rb +5 -0
  30. data/lib/brakeman/report.rb +7 -0
  31. data/lib/brakeman/report/ignore/config.rb +4 -0
  32. data/lib/brakeman/report/report_sarif.rb +114 -0
  33. data/lib/brakeman/report/report_text.rb +37 -16
  34. data/lib/brakeman/scanner.rb +4 -1
  35. data/lib/brakeman/tracker.rb +3 -1
  36. data/lib/brakeman/tracker/config.rb +6 -4
  37. data/lib/brakeman/tracker/constants.rb +8 -7
  38. data/lib/brakeman/tracker/controller.rb +1 -1
  39. data/lib/brakeman/util.rb +18 -2
  40. data/lib/brakeman/version.rb +1 -1
  41. data/lib/brakeman/warning_codes.rb +6 -0
  42. data/lib/ruby_parser/bm_sexp.rb +9 -9
  43. metadata +22 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92ecc405f5d8aa44662d99820f962df8e9b2fe6391837b06639511c7cb7a24bc
4
- data.tar.gz: e991cb7e2732104d3859973aedad74ddce99157f5143c0799c90c2c489289e44
3
+ metadata.gz: d0d7f92e4d46129b7c1861da8af2bd27a0127640865d04dacc07e92dfcc2457a
4
+ data.tar.gz: a917080c19ddeed2b76e9509e9ffc9cfde9ff103f506085ee22681c5d5feef4c
5
5
  SHA512:
6
- metadata.gz: 6fc22f32bfead785a7fe0b5ac06289b323b2a047528f4d1da238b8e0d233ecfabb37a869a51c72698974d9b15e7818d47ef2fafc8dd57fc578bce46c3f3a29b3
7
- data.tar.gz: 5b96b57238d6e2813dbd83744c32ba546e116e205d0b3546bc52010621394ee7c8f012c258155aed021010e535c8f8ee706108059f7c8ef54019a66a25658d03
6
+ metadata.gz: 16bfcae603909f9a89719fdb3f92e7d5d75cabe4285e5b40bdff759da2cbc82f361b6c190a7b9f0d5fa1199e1bd9f39e17e9894966ddf646fba9463db1089a5f
7
+ data.tar.gz: 766484db48898d8495a3ade3930edf52d508267f134b581938f426d43684c0bdd1929c3c0bc96cd73ce7e9c16e975e5b3fa24e7911f83c84fb396bf30349b830
data/CHANGES.md CHANGED
@@ -1,3 +1,42 @@
1
+ # 4.10.1 - 2020-12-24
2
+
3
+ * Declare REXML as a dependency (Ruby 3.0 compatibility)
4
+ * Use `Sexp#sexp_body` instead of `Sexp#[..]` (Ruby 3.0 compatibility)
5
+ * Prevent render loops when template names are absolute paths
6
+ * Ensure RubyParser is passed file path as a String
7
+ * Support new Haml 5.2.0 escaping method
8
+
9
+ # 4.10.0 - 2020-09-28
10
+
11
+ * Add SARIF report format (Steve Winton)
12
+
13
+ # 4.9.1 - 2020-09-04
14
+
15
+ * Check `chomp`ed strings for SQL injection
16
+ * Use version from `active_record` for non-Rails apps (Ulysse Buonomo)
17
+ * Always set line number for joined arrays
18
+ * Avoid warning about missing `attr_accessible` if `protected_attributes` gem is used
19
+
20
+ # 4.9.0 - 2020-08-04
21
+
22
+ * Add check for CVE-2020-8166 (Jamie Finnigan)
23
+ * Avoid warning when `safe_yaml` is used via `YAML.load(..., safe: true)`
24
+ * Add check for user input in `ERB.new` (Matt Hickman)
25
+ * Add `--ensure-ignore-notes` (Eli Block)
26
+ * Remove whitelist/blacklist language, add clarifications
27
+ * Do not warn about mass assignment with `params.permit!.slice`
28
+ * Add "full call" information to call index results
29
+ * Ignore `params.permit!` in path helpers
30
+ * Treat `Dir.glob` as safe source of values in guards
31
+ * Always scan `environment.rb`
32
+
33
+ # 4.8.2 - 2020-05-12
34
+
35
+ * Add check for CVE-2020-8159
36
+ * Fix `authenticate_or_request_with_http_basic` check for passed blocks (Hugo Corbucci)
37
+ * Add `--text-fields` option
38
+ * Add check for escaping HTML entities in JSON configuration
39
+
1
40
  # 4.8.1 - 2020-04-06
2
41
 
3
42
  * Check SQL query strings using `String#strip` or `String.squish`
data/README.md CHANGED
@@ -16,9 +16,11 @@ Using RubyGems:
16
16
 
17
17
  Using Bundler:
18
18
 
19
- group :development do
20
- gem 'brakeman'
21
- end
19
+ ```ruby
20
+ group :development do
21
+ gem 'brakeman'
22
+ end
23
+ ```
22
24
 
23
25
  Using Docker:
24
26
 
@@ -20,6 +20,10 @@ module Brakeman
20
20
  #option is set
21
21
  Errors_Found_Exit_Code = 7
22
22
 
23
+ #Exit code returned when an ignored warning has no note and
24
+ #--ensure-ignore-notes is set
25
+ Empty_Ignore_Note_Exit_Code = 8
26
+
23
27
  @debug = false
24
28
  @quiet = false
25
29
  @loaded_dependencies = []
@@ -233,6 +237,8 @@ module Brakeman
233
237
  [:to_table]
234
238
  when :junit, :to_junit
235
239
  [:to_junit]
240
+ when :sarif, :to_sarif
241
+ [:to_sarif]
236
242
  else
237
243
  [:to_text]
238
244
  end
@@ -262,6 +268,8 @@ module Brakeman
262
268
  :to_table
263
269
  when /\.junit$/i
264
270
  :to_junit
271
+ when /\.sarif$/i
272
+ :to_sarif
265
273
  else
266
274
  :to_text
267
275
  end
@@ -498,6 +506,18 @@ module Brakeman
498
506
  end
499
507
  end
500
508
 
509
+ # Returns an array of alert fingerprints for any ignored warnings without
510
+ # notes found in the specified ignore file (if it exists).
511
+ def self.ignore_file_entries_with_empty_notes file
512
+ return [] unless file
513
+
514
+ require 'brakeman/report/ignore/config'
515
+
516
+ config = IgnoreConfig.new(file, nil)
517
+ config.read_from_file
518
+ config.already_ignored_entries_with_empty_notes.map { |i| i[:fingerprint] }
519
+ end
520
+
501
521
  def self.filter_warnings tracker, options
502
522
  require 'brakeman/report/ignore/config'
503
523
 
@@ -467,7 +467,7 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
467
467
  end
468
468
 
469
469
  def gemfile_or_environment gem_name = :rails
470
- if gem_name and info = tracker.config.get_gem(gem_name)
470
+ if gem_name and info = tracker.config.get_gem(gem_name.to_sym)
471
471
  info
472
472
  elsif @app_tree.exists?("Gemfile")
473
473
  @app_tree.file_path "Gemfile"
@@ -57,6 +57,8 @@ class Brakeman::CheckBasicAuth < Brakeman::BaseCheck
57
57
 
58
58
  # Check if the block of a result contains a comparison of password to string
59
59
  def include_password_literal? result
60
+ return false if result[:block_args].nil?
61
+
60
62
  @password_var = result[:block_args].last
61
63
  @include_password = false
62
64
  process result[:block]
@@ -0,0 +1,28 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckCSRFTokenForgeryCVE < Brakeman::BaseCheck
4
+ Brakeman::Checks.add self
5
+
6
+ @description = "Checks for versions with CSRF token forgery vulnerability (CVE-2020-8166)"
7
+
8
+ def run_check
9
+ fix_version = case
10
+ when version_between?('0.0.0', '5.2.4.2')
11
+ '5.2.4.3'
12
+ when version_between?('6.0.0', '6.0.3')
13
+ '6.0.3.1'
14
+ else
15
+ nil
16
+ end
17
+
18
+ if fix_version
19
+ warn :warning_type => "Cross-Site Request Forgery",
20
+ :warning_code => :CVE_2020_8166,
21
+ :message => msg(msg_version(rails_version), " has a vulnerability that may allow CSRF token forgery. Upgrade to ", msg_version(fix_version), " or patch"),
22
+ :confidence => :medium,
23
+ :gem_info => gemfile_or_environment,
24
+ :link => "https://groups.google.com/g/rubyonrails-security/c/NOjKiGeXUgw"
25
+ end
26
+ end
27
+ end
28
+
@@ -13,7 +13,23 @@ class Brakeman::CheckDeserialize < Brakeman::BaseCheck
13
13
  end
14
14
 
15
15
  def check_yaml
16
- check_methods :YAML, :load, :load_documents, :load_stream, :parse_documents, :parse_stream
16
+ check_methods :YAML, :load_documents, :load_stream, :parse_documents, :parse_stream
17
+
18
+ # Check for safe_yaml gem use with YAML.load(..., safe: true)
19
+ if uses_safe_yaml?
20
+ tracker.find_call(target: :YAML, method: :load).each do |result|
21
+ call = result[:call]
22
+ options = call.second_arg
23
+
24
+ if hash? options and true? hash_access(options, :safe)
25
+ next
26
+ else
27
+ check_deserialize result, :YAML
28
+ end
29
+ end
30
+ else
31
+ check_methods :YAML, :load
32
+ end
17
33
  end
18
34
 
19
35
  def check_csv
@@ -102,4 +118,8 @@ class Brakeman::CheckDeserialize < Brakeman::BaseCheck
102
118
 
103
119
  false
104
120
  end
121
+
122
+ def uses_safe_yaml?
123
+ tracker.config.has_gem? :safe_yaml
124
+ end
105
125
  end
@@ -208,7 +208,7 @@ class Brakeman::CheckExecute < Brakeman::BaseCheck
208
208
  if node_type? e, :if
209
209
  # If we're in a conditional, evaluate the `then` and `else` clauses to
210
210
  # see if they're dangerous.
211
- if res = dangerous?(e.values[1..-1])
211
+ if res = dangerous?(e.sexp_body.sexp_body)
212
212
  return res
213
213
  end
214
214
  elsif node_type? e, :or, :evstr, :dstr
@@ -0,0 +1,38 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckJSONEntityEscape < Brakeman::BaseCheck
4
+ Brakeman::Checks.add self
5
+
6
+ @description = "Check if HTML escaping is disabled for JSON output"
7
+
8
+ def run_check
9
+ check_config_setting
10
+ check_manual_disable
11
+ end
12
+
13
+ def check_config_setting
14
+ if false? tracker.config.rails.dig(:active_support, :escape_html_entities_in_json)
15
+ warn :warning_type => "Cross-Site Scripting",
16
+ :warning_code => :json_html_escape_config,
17
+ :message => msg("HTML entities in JSON are not escaped by default"),
18
+ :confidence => :medium,
19
+ :file => "config/environments/production.rb",
20
+ :line => 1
21
+ end
22
+ end
23
+
24
+ def check_manual_disable
25
+ tracker.find_call(targets: [:ActiveSupport, :'ActiveSupport::JSON::Encoding'], method: :escape_html_entities_in_json=).each do |result|
26
+ setting = result[:call].first_arg
27
+
28
+ if false? setting
29
+ warn :result => result,
30
+ :warning_type => "Cross-Site Scripting",
31
+ :warning_code => :json_html_escape_module,
32
+ :message => msg("HTML entities in JSON are not escaped by default"),
33
+ :confidence => :medium,
34
+ :file => "config/environments/production.rb"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -160,12 +160,27 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck
160
160
  # Look for and warn about uses of Parameters#permit! for mass assignment
161
161
  def check_permit!
162
162
  tracker.find_call(:method => :permit!, :nested => true).each do |result|
163
- if params? result[:call].target and not result[:chain].include? :slice
164
- warn_on_permit! result
163
+ if params? result[:call].target
164
+ unless inside_safe_method? result or calls_slice? result
165
+ warn_on_permit! result
166
+ end
165
167
  end
166
168
  end
167
169
  end
168
170
 
171
+ # Ignore blah_some_path(params.permit!)
172
+ def inside_safe_method? result
173
+ parent_call = result.dig(:parent, :call)
174
+
175
+ call? parent_call and
176
+ parent_call.method.match(/_path$/)
177
+ end
178
+
179
+ def calls_slice? result
180
+ result[:chain].include? :slice or
181
+ (result[:full_call] and result[:full_call][:chain].include? :slice)
182
+ end
183
+
169
184
  # Look for actual use of params in mass assignment to avoid
170
185
  # warning about uses of Parameters#permit! without any mass assignment
171
186
  # or when mass assignment is restricted by model instead.
@@ -191,7 +206,7 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck
191
206
  warn :result => result,
192
207
  :warning_type => "Mass Assignment",
193
208
  :warning_code => :mass_assign_permit!,
194
- :message => "Parameters should be whitelisted for mass assignment",
209
+ :message => msg('Specify exact keys allowed for mass assignment instead of using ', msg_code('permit!'), ' which allows any keys'),
195
210
  :confidence => confidence
196
211
  end
197
212
 
@@ -203,7 +218,7 @@ class Brakeman::CheckMassAssignment < Brakeman::BaseCheck
203
218
  warn :result => result,
204
219
  :warning_type => "Mass Assignment",
205
220
  :warning_code => :mass_assign_permit_all,
206
- :message => "Parameters should be whitelisted for mass assignment",
221
+ :message => msg('Mass assignment is globally enabled. Disable and specify exact keys using ', msg_code('params.permit'), ' instead'),
207
222
  :confidence => :high
208
223
  end
209
224
  end
@@ -8,7 +8,7 @@ require 'brakeman/checks/base_check'
8
8
  class Brakeman::CheckModelAttrAccessible < Brakeman::BaseCheck
9
9
  Brakeman::Checks.add self
10
10
 
11
- @description = "Reports models which have dangerous attributes defined under the attr_accessible whitelist."
11
+ @description = "Reports models which have dangerous attributes defined via attr_accessible"
12
12
 
13
13
  SUSP_ATTRS = [
14
14
  [:admin, :high], # Very dangerous unless some Rails authorization used
@@ -8,7 +8,7 @@ class Brakeman::CheckModelAttributes < Brakeman::BaseCheck
8
8
  @description = "Reports models which do not use attr_restricted and warns on models that use attr_protected"
9
9
 
10
10
  def run_check
11
- return if mass_assign_disabled?
11
+ return if mass_assign_disabled? or tracker.config.has_gem?(:protected_attributes)
12
12
 
13
13
  #Roll warnings into one warning for all models
14
14
  if tracker.options[:collapse_mass_assignment]
@@ -0,0 +1,37 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckPageCachingCVE < Brakeman::BaseCheck
4
+ Brakeman::Checks.add self
5
+
6
+ @description = "Check for page caching vulnerability (CVE-2020-8159)"
7
+
8
+ def run_check
9
+ gem_name = 'actionpack-page_caching'
10
+ gem_version = tracker.config.gem_version(gem_name.to_sym)
11
+ upgrade_version = '1.2.2'
12
+ cve = 'CVE-2020-8159'
13
+
14
+ return unless gem_version and version_between?('0.0.0', '1.2.1', gem_version)
15
+
16
+ message = msg("Directory traversal vulnerability in ", msg_version(gem_version, gem_name), " ", msg_cve(cve), ". Upgrade to ", msg_version(upgrade_version, gem_name))
17
+
18
+ if uses_caches_page?
19
+ confidence = :high
20
+ else
21
+ confidence = :weak
22
+ end
23
+
24
+ warn :warning_type => 'Directory Traversal',
25
+ :warning_code => :CVE_2020_8159,
26
+ :message => message,
27
+ :confidence => confidence,
28
+ :link_path => 'https://groups.google.com/d/msg/rubyonrails-security/CFRVkEytdP8/c5gmICECAgAJ',
29
+ :gem_info => gemfile_or_environment(gem_name)
30
+ end
31
+
32
+ def uses_caches_page?
33
+ tracker.controllers.any? do |name, controller|
34
+ controller.options.has_key? :caches_page
35
+ end
36
+ end
37
+ end
@@ -3,7 +3,7 @@ require 'brakeman/checks/base_check'
3
3
  class Brakeman::CheckPermitAttributes < Brakeman::BaseCheck
4
4
  Brakeman::Checks.add self
5
5
 
6
- @description = "Warn on potentially dangerous attributes whitelisted via permit"
6
+ @description = "Warn on potentially dangerous attributes allowed via permit"
7
7
 
8
8
  SUSPICIOUS_KEYS = {
9
9
  admin: :high,
@@ -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
@@ -4,8 +4,8 @@ require 'brakeman/checks/base_check'
4
4
  #
5
5
  # skip_before_filter :verify_authenticity_token, :except => [...]
6
6
  #
7
- #which is essentially a blacklist approach (no actions are checked EXCEPT the
8
- #ones listed) versus a whitelist approach (ONLY the actions listed will skip
7
+ #which is essentially a skip-by-default approach (no actions are checked EXCEPT the
8
+ #ones listed) versus a enforce-by-default approach (ONLY the actions listed will skip
9
9
  #the check)
10
10
  class Brakeman::CheckSkipBeforeFilter < Brakeman::BaseCheck
11
11
  Brakeman::Checks.add self
@@ -26,7 +26,7 @@ class Brakeman::CheckSkipBeforeFilter < Brakeman::BaseCheck
26
26
  warn :class => controller.name, #ugh this should be a controller warning, too
27
27
  :warning_type => "Cross-Site Request Forgery",
28
28
  :warning_code => :csrf_blacklist,
29
- :message => msg("Use whitelist (", msg_code(":only => [..]"), ") when skipping CSRF check"),
29
+ :message => msg("List specific actions (", msg_code(":only => [..]"), ") when skipping CSRF check"),
30
30
  :code => filter,
31
31
  :confidence => :medium,
32
32
  :file => controller.file
@@ -35,7 +35,7 @@ class Brakeman::CheckSkipBeforeFilter < Brakeman::BaseCheck
35
35
  warn :controller => controller.name,
36
36
  :warning_code => :auth_blacklist,
37
37
  :warning_type => "Authentication",
38
- :message => msg("Use whitelist (", msg_code(":only => [..]"), ") when skipping authentication"),
38
+ :message => msg("List specific actions (", msg_code(":only => [..]"), ") when skipping authentication"),
39
39
  :code => filter,
40
40
  :confidence => :medium,
41
41
  :link_path => "authentication_whitelist",
@@ -393,7 +393,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
393
393
  nil
394
394
  end
395
395
 
396
- TO_STRING_METHODS = [:to_s, :squish, :strip, :strip_heredoc]
396
+ TO_STRING_METHODS = [:chomp, :to_s, :squish, :strip, :strip_heredoc]
397
397
 
398
398
  #Returns value if interpolated value is not something safe
399
399
  def unsafe_string_interp? exp
@@ -0,0 +1,32 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckTemplateInjection < Brakeman::BaseCheck
4
+ Brakeman::Checks.add self
5
+
6
+ @description = "Searches for evaluation of user input through template injection"
7
+
8
+ #Process calls
9
+ def run_check
10
+ Brakeman.debug "Finding ERB.new calls"
11
+ erb_calls = tracker.find_call :target => :ERB, :method => :new, :nested => true
12
+
13
+ Brakeman.debug "Processing ERB.new calls"
14
+ erb_calls.each do |call|
15
+ process_result call
16
+ end
17
+ end
18
+
19
+ #Warns if eval includes user input
20
+ def process_result result
21
+ return unless original? result
22
+
23
+ if input = include_user_input?(result[:call].arglist)
24
+ warn :result => result,
25
+ :warning_type => "Template Injection",
26
+ :warning_code => :erb_template_injection,
27
+ :message => msg(msg_input(input), " used directly in ", msg_code("ERB"), " template, which might enable remote code execution"),
28
+ :user_input => input,
29
+ :confidence => :high
30
+ end
31
+ end
32
+ end
@@ -102,6 +102,13 @@ module Brakeman
102
102
  app_path = "."
103
103
  end
104
104
 
105
+ if options[:ensure_ignore_notes] and options[:previous_results_json]
106
+ warn '[Notice] --ensure-ignore-notes may not be used at the same ' \
107
+ 'time as --compare. Deactivating --ensure-ignore-notes. ' \
108
+ 'Please see `brakeman --help` for valid options'
109
+ options[:ensure_ignore_notes] = false
110
+ end
111
+
105
112
  return options, app_path
106
113
  end
107
114
 
@@ -115,7 +122,20 @@ module Brakeman
115
122
 
116
123
  # Runs a regular report based on the options provided.
117
124
  def regular_report options
118
- tracker = run_brakeman options
125
+ tracker = run_brakeman options
126
+
127
+ ensure_ignore_notes_failed = false
128
+ if tracker.options[:ensure_ignore_notes]
129
+ fingerprints = Brakeman::ignore_file_entries_with_empty_notes tracker.ignored_filter&.file
130
+
131
+ unless fingerprints.empty?
132
+ ensure_ignore_notes_failed = true
133
+ warn '[Error] Notes required for all ignored warnings when ' \
134
+ '--ensure-ignore-notes is set. No notes provided for these ' \
135
+ 'warnings: '
136
+ fingerprints.each { |f| warn f }
137
+ end
138
+ end
119
139
 
120
140
  if tracker.options[:exit_on_warn] and not tracker.filtered_warnings.empty?
121
141
  quit Brakeman::Warnings_Found_Exit_Code
@@ -124,6 +144,10 @@ module Brakeman
124
144
  if tracker.options[:exit_on_error] and tracker.errors.any?
125
145
  quit Brakeman::Errors_Found_Exit_Code
126
146
  end
147
+
148
+ if ensure_ignore_notes_failed
149
+ quit Brakeman::Empty_Ignore_Note_Exit_Code
150
+ end
127
151
  end
128
152
 
129
153
  # Actually run Brakeman.
@@ -33,7 +33,12 @@ module Brakeman
33
33
  end
34
34
  end
35
35
 
36
+ # _path_ can be a string or a Brakeman::FilePath
36
37
  def parse_ruby input, path
38
+ if path.is_a? Brakeman::FilePath
39
+ path = path.relative
40
+ end
41
+
37
42
  begin
38
43
  Brakeman.debug "Parsing #{path}"
39
44
  RubyParser.new.parse input, path, @timeout
@@ -67,6 +67,10 @@ module Brakeman::Options
67
67
  options[:ensure_latest] = true
68
68
  end
69
69
 
70
+ opts.on "--ensure-ignore-notes", "Fail when an ignored warnings does not include a note" do
71
+ options[:ensure_ignore_notes] = true
72
+ end
73
+
70
74
  opts.on "-3", "--rails3", "Force Rails 3 mode" do
71
75
  options[:rails3] = true
72
76
  end
@@ -225,7 +229,7 @@ module Brakeman::Options
225
229
 
226
230
  opts.on "-f",
227
231
  "--format TYPE",
228
- [:pdf, :text, :html, :csv, :tabs, :json, :markdown, :codeclimate, :cc, :plain, :table, :junit],
232
+ [:pdf, :text, :html, :csv, :tabs, :json, :markdown, :codeclimate, :cc, :plain, :table, :junit, :sarif],
229
233
  "Specify output formats. Default is text" do |type|
230
234
 
231
235
  type = "s" if type == :text
@@ -301,6 +305,22 @@ module Brakeman::Options
301
305
  options[:github_repo] = repo
302
306
  end
303
307
 
308
+ opts.on "--text-fields field1,field2,etc.", Array, "Specify fields for text report format" do |format|
309
+ valid_options = [:category, :category_id, :check, :code, :confidence, :file, :fingerprint, :line, :link, :message, :render_path]
310
+
311
+ options[:text_fields] = format.map(&:to_sym)
312
+
313
+ if options[:text_fields] == [:all]
314
+ options[:text_fields] = valid_options
315
+ else
316
+ invalid_options = (options[:text_fields] - valid_options)
317
+
318
+ unless invalid_options.empty?
319
+ raise OptionParser::ParseError, "\nInvalid format options: #{invalid_options.inspect}"
320
+ end
321
+ end
322
+ end
323
+
304
324
  opts.on "-w",
305
325
  "--confidence-level LEVEL",
306
326
  ["1", "2", "3"],
@@ -82,7 +82,6 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
82
82
  def replace exp, int = 0
83
83
  return exp if int > 3
84
84
 
85
-
86
85
  if replacement = env[exp] and not duplicate? replacement
87
86
  replace(replacement.deep_clone(exp.line), int + 1)
88
87
  elsif tracker and replacement = tracker.constant_lookup(exp) and not duplicate? replacement
@@ -237,7 +236,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
237
236
  env[target_var] = target
238
237
  return target
239
238
  elsif string? target and string_interp? first_arg
240
- exp = Sexp.new(:dstr, target.value + first_arg[1]).concat(first_arg[2..-1])
239
+ exp = Sexp.new(:dstr, target.value + first_arg[1]).concat(first_arg.sexp_body(2))
241
240
  env[target_var] = exp
242
241
  elsif string? first_arg and string_interp? target
243
242
  if string? target.last
@@ -731,14 +730,14 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
731
730
  def array_include_all_literals? exp
732
731
  call? exp and
733
732
  exp.method == :include? and
734
- all_literals? exp.target
733
+ (all_literals? exp.target or dir_glob? exp.target)
735
734
  end
736
735
 
737
736
  def array_detect_all_literals? exp
738
737
  call? exp and
739
738
  [:detect, :find].include? exp.method and
740
739
  exp.first_arg.nil? and
741
- all_literals? exp.target
740
+ (all_literals? exp.target or dir_glob? exp.target)
742
741
  end
743
742
 
744
743
  #Sets @inside_if = true
@@ -942,7 +941,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
942
941
  args = exp.args
943
942
  exp.pop # remove last arg
944
943
  if args.length > 1
945
- exp.arglist = args[1..-1]
944
+ exp.arglist = args.sexp_body
946
945
  end
947
946
  end
948
947
 
@@ -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
@@ -20,6 +20,7 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
20
20
  @current_template = opts[:template]
21
21
  @current_file = opts[:file]
22
22
  @current_call = nil
23
+ @full_call = nil
23
24
  process exp
24
25
  end
25
26
 
@@ -137,7 +138,8 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
137
138
  :call => exp,
138
139
  :nested => false,
139
140
  :location => make_location,
140
- :parent => @current_call }.freeze
141
+ :parent => @current_call,
142
+ :full_call => @full_call }.freeze
141
143
  end
142
144
 
143
145
  #Gets the target of a call as a Symbol
@@ -214,34 +216,47 @@ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
214
216
  #Return info hash for a call Sexp
215
217
  def create_call_hash exp
216
218
  target = get_target exp.target
217
-
218
- if call? target or node_type? target, :dxstr # need to index `` even if target of a call
219
- already_in_target = @in_target
220
- @in_target = true
221
- process target
222
- @in_target = already_in_target
223
-
224
- target = get_target(target, :include_calls)
225
- end
219
+ target_symbol = get_target(target, :include_calls)
226
220
 
227
221
  method = exp.method
228
222
 
229
223
  call_hash = {
230
- :target => target,
224
+ :target => target_symbol,
231
225
  :method => method,
232
226
  :call => exp,
233
227
  :nested => @in_target,
234
228
  :chain => get_chain(exp),
235
229
  :location => make_location,
236
- :parent => @current_call
230
+ :parent => @current_call,
231
+ :full_call => @full_call
237
232
  }
238
233
 
234
+ unless @in_target
235
+ @full_call = call_hash
236
+ end
237
+
238
+ # Process up the call chain
239
+ if call? target or node_type? target, :dxstr # need to index `` even if target of a call
240
+ already_in_target = @in_target
241
+ @in_target = true
242
+ process target
243
+ @in_target = already_in_target
244
+ end
245
+
246
+ # Process call arguments
247
+ # but add the current call as the 'parent'
248
+ # to any calls in the arguments
239
249
  old_parent = @current_call
240
250
  @current_call = call_hash
241
251
 
252
+ # Do not set @full_call when processing arguments
253
+ old_full_call = @full_call
254
+ @full_call = nil
255
+
242
256
  process_call_args exp
243
257
 
244
258
  @current_call = old_parent
259
+ @full_call = old_full_call
245
260
 
246
261
  call_hash
247
262
  end
@@ -88,7 +88,7 @@ class Brakeman::OutputProcessor < Ruby2Ruby
88
88
 
89
89
  def process_iter exp
90
90
  call = process exp[1]
91
- block = process_rlist exp[3..-1]
91
+ block = process_rlist exp.sexp_body(3)
92
92
  out = "#{call} do\n #{block}\n end"
93
93
 
94
94
  out
@@ -20,6 +20,11 @@ class Brakeman::TemplateAliasProcessor < Brakeman::AliasProcessor
20
20
 
21
21
  #Process template
22
22
  def process_template name, args, _, line = nil
23
+ # Strip forward slash from beginning of template path.
24
+ # This also happens in RenderHelper#process_template but
25
+ # we need it here too to accurately avoid circular renders below.
26
+ name = name.to_s.gsub(/^\//, "")
27
+
23
28
  if @called_from
24
29
  if @called_from.include_template? name
25
30
  Brakeman.debug "Skipping circular render from #{@template.name} to #{name}"
@@ -43,6 +43,8 @@ class Brakeman::Report
43
43
  when :to_junit
44
44
  require_report 'junit'
45
45
  Brakeman::Report::JUnit
46
+ when :to_sarif
47
+ return self.to_sarif
46
48
  else
47
49
  raise "Invalid format: #{format}. Should be one of #{VALID_FORMATS.inspect}"
48
50
  end
@@ -85,6 +87,11 @@ class Brakeman::Report
85
87
  alias to_plain to_text
86
88
  alias to_s to_text
87
89
 
90
+ def to_sarif
91
+ require_report 'sarif'
92
+ generate Brakeman::Report::SARIF
93
+ end
94
+
88
95
  def generate reporter
89
96
  reporter.new(@tracker).generate_report
90
97
  end
@@ -94,6 +94,10 @@ module Brakeman
94
94
  end
95
95
  end
96
96
 
97
+ def already_ignored_entries_with_empty_notes
98
+ @already_ignored.select { |i| i if i[:note].strip.empty? }
99
+ end
100
+
97
101
  # Read configuration to file
98
102
  def read_from_file file = @file
99
103
  if File.exist? file
@@ -0,0 +1,114 @@
1
+ class Brakeman::Report::SARIF < Brakeman::Report::Base
2
+ def generate_report
3
+ sarif_log = {
4
+ :version => '2.1.0',
5
+ :$schema => 'https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json',
6
+ :runs => runs,
7
+ }
8
+ JSON.pretty_generate sarif_log
9
+ end
10
+
11
+ def runs
12
+ [
13
+ {
14
+ :tool => {
15
+ :driver => {
16
+ :name => 'Brakeman',
17
+ :informationUri => 'https://brakemanscanner.org',
18
+ :semanticVersion => Brakeman::Version,
19
+ :rules => rules,
20
+ },
21
+ },
22
+ :results => results,
23
+ },
24
+ ]
25
+ end
26
+
27
+ def rules
28
+ @rules ||= unique_warnings_by_warning_code.map do |warning|
29
+ rule_id = render_id warning
30
+ check_name = warning.check.gsub(/^Brakeman::Check/, '')
31
+ check_description = render_message check_descriptions[check_name]
32
+ {
33
+ :id => rule_id,
34
+ :name => "#{check_name}/#{warning.warning_type}",
35
+ :fullDescription => {
36
+ :text => check_description,
37
+ },
38
+ :helpUri => warning.link,
39
+ :help => {
40
+ :text => "More info: #{warning.link}.",
41
+ :markdown => "[More info](#{warning.link}).",
42
+ },
43
+ :properties => {
44
+ :tags => [check_name],
45
+ },
46
+ }
47
+ end
48
+ end
49
+
50
+ def results
51
+ @results ||= all_warnings.map do |warning|
52
+ rule_id = render_id warning
53
+ result_level = infer_level warning
54
+ message_text = render_message warning.message.to_s
55
+ result = {
56
+ :ruleId => rule_id,
57
+ :ruleIndex => rules.index { |r| r[:id] == rule_id },
58
+ :level => result_level,
59
+ :message => {
60
+ :text => message_text,
61
+ },
62
+ :locations => [
63
+ :physicalLocation => {
64
+ :artifactLocation => {
65
+ :uri => warning.file.relative,
66
+ :uriBaseId => '%SRCROOT%',
67
+ },
68
+ :region => {
69
+ :startLine => warning.line.is_a?(Integer) ? warning.line : 1,
70
+ },
71
+ },
72
+ ],
73
+ }
74
+
75
+ result
76
+ end
77
+ end
78
+
79
+ # Returns a hash of all check descriptions, keyed by check namne
80
+ def check_descriptions
81
+ @check_descriptions ||= Brakeman::Checks.checks.map do |check|
82
+ [check.name.gsub(/^Check/, ''), check.description]
83
+ end.to_h
84
+ end
85
+
86
+ # Returns a de-duplicated set of warnings, used to generate rules
87
+ def unique_warnings_by_warning_code
88
+ @unique_warnings_by_warning_code ||= all_warnings.uniq { |w| w.warning_code }
89
+ end
90
+
91
+ def render_id warning
92
+ # Include alpha prefix to provide 'compiler error' appearance
93
+ "BRAKE#{'%04d' % warning.warning_code}" # 46 becomes BRAKE0046, for example
94
+ end
95
+
96
+ def render_message message
97
+ # Ensure message ends with a period
98
+ if message.end_with? "."
99
+ message
100
+ else
101
+ "#{message}."
102
+ end
103
+ end
104
+
105
+ def infer_level warning
106
+ # Infer result level from warning confidence
107
+ @@levels_from_confidence ||= Hash.new('warning').update({
108
+ 0 => 'error', # 0 represents 'high confidence', which we infer as 'error'
109
+ 1 => 'warning', # 1 represents 'medium confidence' which we infer as 'warning'
110
+ 2 => 'note', # 2 represents 'weak, or low, confidence', which we infer as 'note'
111
+ })
112
+ @@levels_from_confidence[warning.confidence]
113
+ end
114
+ end
@@ -145,24 +145,45 @@ class Brakeman::Report::Text < Brakeman::Report::Base
145
145
  end
146
146
 
147
147
  def output_warning w
148
- out = [
149
- label('Confidence', confidence(w.confidence)),
150
- label('Category', w.warning_type.to_s),
151
- label('Check', w.check.gsub(/^Brakeman::Check/, '')),
148
+ text_format = tracker.options[:text_fields] ||
149
+ [:confidence, :category, :check, :message, :code, :file, :line]
150
+
151
+ text_format.map do |option|
152
+ format_line(w, option)
153
+ end.compact
154
+ end
155
+
156
+ def format_line w, option
157
+ case option
158
+ when :confidence
159
+ label('Confidence', confidence(w.confidence))
160
+ when :category
161
+ label('Category', w.warning_type.to_s)
162
+ when :check
163
+ label('Check', w.check.gsub(/^Brakeman::Check/, ''))
164
+ when :message
152
165
  label('Message', w.message)
153
- ]
154
-
155
- if w.code
156
- out << label('Code', format_code(w))
157
- end
158
-
159
- out << label('File', warning_file(w))
160
-
161
- if w.line
162
- out << label('Line', w.line)
166
+ when :code
167
+ if w.code
168
+ label('Code', format_code(w))
169
+ end
170
+ when :file
171
+ label('File', warning_file(w))
172
+ when :line
173
+ if w.line
174
+ label('Line', w.line)
175
+ end
176
+ when :link
177
+ label('Link', w.link)
178
+ when :fingerprint
179
+ label('Fingerprint', w.fingerprint)
180
+ when :category_id
181
+ label('Category ID', w.warning_code)
182
+ when :render_path
183
+ if w.called_from
184
+ label('Render Path', w.called_from.join(" > "))
185
+ end
163
186
  end
164
-
165
- out
166
187
  end
167
188
 
168
189
  def double_space title, values
@@ -94,11 +94,14 @@ class Brakeman::Scanner
94
94
  #
95
95
  #Stores parsed information in tracker.config
96
96
  def process_config
97
+ # Sometimes folks like to put constants in environment.rb
98
+ # so let's always process it even for newer Rails versions
99
+ process_config_file "environment.rb"
100
+
97
101
  if options[:rails3] or options[:rails4] or options[:rails5] or options[:rails6]
98
102
  process_config_file "application.rb"
99
103
  process_config_file "environments/production.rb"
100
104
  else
101
- process_config_file "environment.rb"
102
105
  process_config_file "gems.rb"
103
106
  end
104
107
 
@@ -198,8 +198,10 @@ class Brakeman::Tracker
198
198
  @constants.add name, value, context unless @options[:disable_constant_tracking]
199
199
  end
200
200
 
201
+ # This method does not return all constants at this time,
202
+ # just ones with "simple" values.
201
203
  def constant_lookup name
202
- @constants.get_literal name unless @options[:disable_constant_tracking]
204
+ @constants.get_simple_value name unless @options[:disable_constant_tracking]
203
205
  end
204
206
 
205
207
  def find_class name
@@ -54,7 +54,7 @@ module Brakeman
54
54
  end
55
55
 
56
56
  def gem_version name
57
- extract_version @gems.dig(name, :version)
57
+ extract_version @gems.dig(name.to_sym, :version)
58
58
  end
59
59
 
60
60
  def add_gem name, version, file, line
@@ -67,11 +67,11 @@ module Brakeman
67
67
  end
68
68
 
69
69
  def has_gem? name
70
- !!@gems[name]
70
+ !!@gems[name.to_sym]
71
71
  end
72
72
 
73
73
  def get_gem name
74
- @gems[name]
74
+ @gems[name.to_sym]
75
75
  end
76
76
 
77
77
  def set_rails_version version = nil
@@ -79,7 +79,9 @@ module Brakeman
79
79
  # Only used by Rails2ConfigProcessor right now
80
80
  extract_version(version)
81
81
  else
82
- gem_version(:rails) || gem_version(:railties)
82
+ gem_version(:rails) ||
83
+ gem_version(:railties) ||
84
+ gem_version(:activerecord)
83
85
  end
84
86
 
85
87
  if version
@@ -1,7 +1,10 @@
1
1
  require 'brakeman/processors/output_processor'
2
+ require 'brakeman/util'
2
3
 
3
4
  module Brakeman
4
5
  class Constant
6
+ include Brakeman::Util
7
+
5
8
  attr_reader :name, :name_array, :file, :value, :context
6
9
 
7
10
  def initialize name, value, context = {}
@@ -107,13 +110,11 @@ module Brakeman
107
110
  @constants[base_name] << Constant.new(name, value, context)
108
111
  end
109
112
 
110
- LITERALS = [:lit, :false, :str, :true, :array, :hash]
111
- def literal? exp
112
- exp.is_a? Sexp and LITERALS.include? exp.node_type
113
- end
114
-
115
- def get_literal name
116
- if x = self[name] and literal? x
113
+ # Returns constant values that are not too complicated.
114
+ # Right now that means literal values (string, array, etc.)
115
+ # or calls on Dir.glob(..).whatever.
116
+ def get_simple_value name
117
+ if x = self[name] and (literal? x or dir_glob? x)
117
118
  x
118
119
  else
119
120
  nil
@@ -125,7 +125,7 @@ module Brakeman
125
125
  value = args[-1][2]
126
126
  case value.node_type
127
127
  when :array
128
- filter[option] = value[1..-1].map {|v| v[1] }
128
+ filter[option] = value.sexp_body.map {|v| v[1] }
129
129
  when :lit, :str
130
130
  filter[option] = value[1]
131
131
  else
@@ -293,6 +293,22 @@ module Brakeman::Util
293
293
  exp.is_a? Sexp and types.include? exp.node_type
294
294
  end
295
295
 
296
+ LITERALS = [:lit, :false, :str, :true, :array, :hash]
297
+
298
+ def literal? exp
299
+ exp.is_a? Sexp and LITERALS.include? exp.node_type
300
+ end
301
+
302
+ DIR_CONST = s(:const, :Dir)
303
+
304
+ # Dir.glob(...).whatever
305
+ def dir_glob? exp
306
+ exp = exp.block_call if node_type? exp, :iter
307
+ return unless call? exp
308
+
309
+ (exp.target == DIR_CONST and exp.method == :glob) or dir_glob? exp.target
310
+ end
311
+
296
312
  #Returns true if the given _exp_ contains a :class node.
297
313
  #
298
314
  #Useful for checking if a module is just a module or if it is a namespace.
@@ -305,7 +321,7 @@ module Brakeman::Util
305
321
  if node_type? current, :class
306
322
  return true
307
323
  elsif sexp? current
308
- todo = current[1..-1].concat todo
324
+ todo = current.sexp_body.concat todo
309
325
  end
310
326
  end
311
327
 
@@ -318,7 +334,7 @@ module Brakeman::Util
318
334
  if args.empty? or args.first.empty?
319
335
  #nothing to do
320
336
  elsif node_type? args.first, :arglist
321
- call.concat args.first[1..-1]
337
+ call.concat args.first.sexp_body
322
338
  elsif args.first.node_type.is_a? Sexp #just a list of args
323
339
  call.concat args.first
324
340
  else
@@ -1,3 +1,3 @@
1
1
  module Brakeman
2
- Version = "4.8.1"
2
+ Version = "4.10.1"
3
3
  end
@@ -114,6 +114,12 @@ module Brakeman::WarningCodes
114
114
  :unsafe_cookie_serialization => 110,
115
115
  :reverse_tabnabbing => 111,
116
116
  :mass_assign_permit_all => 112,
117
+ :json_html_escape_config => 113,
118
+ :json_html_escape_module => 114,
119
+ :CVE_2020_8159 => 115,
120
+ :CVE_2020_8166 => 116,
121
+ :erb_template_injection => 117,
122
+
117
123
  :custom_check => 9090,
118
124
  }
119
125
 
@@ -175,7 +175,7 @@ class Sexp
175
175
  start_index = 3
176
176
 
177
177
  if exp.is_a? Sexp and exp.node_type == :arglist
178
- exp = exp[1..-1]
178
+ exp = exp.sexp_body
179
179
  end
180
180
 
181
181
  exp.each_with_index do |e, i|
@@ -198,10 +198,10 @@ class Sexp
198
198
 
199
199
  case self.node_type
200
200
  when :call, :attrasgn, :safe_call, :safe_attrasgn
201
- self[3..-1].unshift :arglist
201
+ self.sexp_body(3).unshift :arglist
202
202
  when :super, :zsuper
203
203
  if self[1]
204
- self[1..-1].unshift :arglist
204
+ self.sexp_body.unshift :arglist
205
205
  else
206
206
  Sexp.new(:arglist)
207
207
  end
@@ -218,13 +218,13 @@ class Sexp
218
218
  case self.node_type
219
219
  when :call, :attrasgn, :safe_call, :safe_attrasgn
220
220
  if self[3]
221
- self[3..-1]
221
+ self.sexp_body(3)
222
222
  else
223
223
  Sexp.new
224
224
  end
225
225
  when :super, :zsuper
226
226
  if self[1]
227
- self[1..-1]
227
+ self.sexp_body
228
228
  else
229
229
  Sexp.new
230
230
  end
@@ -512,7 +512,7 @@ class Sexp
512
512
  self.slice!(index..-1) #Remove old body
513
513
 
514
514
  if exp.first == :rlist
515
- exp = exp[1..-1]
515
+ exp = exp.sexp_body
516
516
  end
517
517
 
518
518
  #Insert new body
@@ -529,11 +529,11 @@ class Sexp
529
529
 
530
530
  case self.node_type
531
531
  when :defn, :class
532
- self[3..-1]
532
+ self.sexp_body(3)
533
533
  when :defs
534
- self[4..-1]
534
+ self.sexp_body(4)
535
535
  when :module
536
- self[2..-1]
536
+ self.sexp_body(2)
537
537
  end
538
538
  end
539
539
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brakeman-min
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.8.1
4
+ version: 4.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Collins
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-07 00:00:00.000000000 Z
11
+ date: 2020-12-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov-html
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.10.2
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 0.10.2
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: ruby_parser
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -146,6 +160,7 @@ files:
146
160
  - lib/brakeman/checks/check_cookie_serialization.rb
147
161
  - lib/brakeman/checks/check_create_with.rb
148
162
  - lib/brakeman/checks/check_cross_site_scripting.rb
163
+ - lib/brakeman/checks/check_csrf_token_forgery_cve.rb
149
164
  - lib/brakeman/checks/check_default_routes.rb
150
165
  - lib/brakeman/checks/check_deserialize.rb
151
166
  - lib/brakeman/checks/check_detailed_exceptions.rb
@@ -164,6 +179,7 @@ files:
164
179
  - lib/brakeman/checks/check_i18n_xss.rb
165
180
  - lib/brakeman/checks/check_jruby_xml.rb
166
181
  - lib/brakeman/checks/check_json_encoding.rb
182
+ - lib/brakeman/checks/check_json_entity_escape.rb
167
183
  - lib/brakeman/checks/check_json_parsing.rb
168
184
  - lib/brakeman/checks/check_link_to.rb
169
185
  - lib/brakeman/checks/check_link_to_href.rb
@@ -176,6 +192,7 @@ files:
176
192
  - lib/brakeman/checks/check_nested_attributes.rb
177
193
  - lib/brakeman/checks/check_nested_attributes_bypass.rb
178
194
  - lib/brakeman/checks/check_number_to_currency.rb
195
+ - lib/brakeman/checks/check_page_caching_cve.rb
179
196
  - lib/brakeman/checks/check_permit_attributes.rb
180
197
  - lib/brakeman/checks/check_quote_table_name.rb
181
198
  - lib/brakeman/checks/check_redirect.rb
@@ -205,6 +222,7 @@ files:
205
222
  - lib/brakeman/checks/check_strip_tags.rb
206
223
  - lib/brakeman/checks/check_symbol_dos.rb
207
224
  - lib/brakeman/checks/check_symbol_dos_cve.rb
225
+ - lib/brakeman/checks/check_template_injection.rb
208
226
  - lib/brakeman/checks/check_translate_bug.rb
209
227
  - lib/brakeman/checks/check_unsafe_reflection.rb
210
228
  - lib/brakeman/checks/check_unscoped_find.rb
@@ -274,6 +292,7 @@ files:
274
292
  - lib/brakeman/report/report_json.rb
275
293
  - lib/brakeman/report/report_junit.rb
276
294
  - lib/brakeman/report/report_markdown.rb
295
+ - lib/brakeman/report/report_sarif.rb
277
296
  - lib/brakeman/report/report_table.rb
278
297
  - lib/brakeman/report/report_tabs.rb
279
298
  - lib/brakeman/report/report_text.rb
@@ -330,7 +349,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
330
349
  - !ruby/object:Gem::Version
331
350
  version: '0'
332
351
  requirements: []
333
- rubygems_version: 3.0.8
352
+ rubygems_version: 3.2.2
334
353
  signing_key:
335
354
  specification_version: 4
336
355
  summary: Security vulnerability scanner for Ruby on Rails.