brakeman-min 6.0.1 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32281be786de7f15331b0a18d3a95ee580824c71ebcaa5793dce46bf9e00eaf5
4
- data.tar.gz: 0b86124af3e493a0e30298e59339026f0bee8decd2a3851894b556fcb2e018a3
3
+ metadata.gz: f3d1ef35f0a458f391c5f4effc1de2e8bdc3d45af179d8f74969cb158c13c49f
4
+ data.tar.gz: f1d3e159e9150c761fb99725b6d428629c9c7a04701f3d7c1ad786401f53c231
5
5
  SHA512:
6
- metadata.gz: 963ea6f98407ab7b887ac6e00a8ab7e6e9388357c7f96bd694e88e80a35e1be337f241fb0bb9708eed5a4f9d418b29c28b37e96fc6a57c9d59b6e032f855ea8a
7
- data.tar.gz: 295ba8cd987f5d26fff77fd204f50b54e64126bd5e700ff8d82789b32bbc58c3d4b4b8e8bc0b58841430d67290d0eb452fa302a428c109d9619b6f4b81d4a289
6
+ metadata.gz: 8ff07cba86602c89f661ae14fa0326568686aaba4c38980fbfcf4e93c0e00e09a021672a42a103f4fd0584511605b6e18fa87cd90515e7a4f19713063f7b6fd2
7
+ data.tar.gz: 79ad89ebc88ea562c8b3111ee9a79b59e52c842a612739aeec50347dcb2cc7f2453eaa084eca434143c64bd6e0af6aca285aaf99c10ddf49c0301ba57c73f500
data/CHANGES.md CHANGED
@@ -1,3 +1,12 @@
1
+ # 6.1.0 - 2023-12-04
2
+
3
+ * Add `--timing` to add timing duration for scan steps
4
+ * Fix keyword splats in filter arguments
5
+ * Add check for unfiltered search with Ransack
6
+ * Fix class method lookup in parent classes
7
+ * Handle `class << self`
8
+ * Add `PG::Connection.escape_string` as a SQL sanitization method (Joévin Soulenq)
9
+
1
10
  # 6.0.1 - 2023-07-20
2
11
 
3
12
  * Accept strings for `load_defaults` version
@@ -0,0 +1,53 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckRansack < Brakeman::BaseCheck
4
+ Brakeman::Checks.add self
5
+
6
+ @description = "Checks for dangerous use of the Ransack library"
7
+
8
+ def run_check
9
+ return unless version_between? "0.0.0", "3.99", tracker.config.gem_version(:ransack)
10
+ check_ransack_calls
11
+ end
12
+
13
+ def check_ransack_calls
14
+ tracker.find_call(method: :ransack, nested: true).each do |result|
15
+ next unless original? result
16
+
17
+ call = result[:call]
18
+ arg = call.first_arg
19
+
20
+ # If an allow list is defined anywhere in the
21
+ # class or super classes, consider it safe
22
+ class_name = result[:chain].first
23
+
24
+ next if ransackable_allow_list?(class_name)
25
+
26
+ if input = has_immediate_user_input?(arg)
27
+ confidence = if tracker.find_class(class_name).nil?
28
+ confidence = :low
29
+ elsif result[:location][:file].relative.include? 'admin'
30
+ confidence = :medium
31
+ else
32
+ confidence = :high
33
+ end
34
+
35
+ message = msg('Unrestricted search using ', msg_code('ransack'), ' library called with ', msg_input(input), '. Limit search by defining ', msg_code('ransackable_attributes'), ' and ', msg_code('ransackable_associations'), ' methods in class or upgrade Ransack to version 4.0.0 or newer')
36
+
37
+ warn result: result,
38
+ warning_type: 'Missing Authorization',
39
+ warning_code: :ransack_search,
40
+ message: message,
41
+ user_input: input,
42
+ confidence: confidence,
43
+ cwe_id: [862],
44
+ link: 'https://positive.security/blog/ransack-data-exfiltration'
45
+ end
46
+ end
47
+ end
48
+
49
+ def ransackable_allow_list? class_name
50
+ tracker.find_method(:ransackable_attributes, class_name, :class) and
51
+ tracker.find_method(:ransackable_associations, class_name, :class)
52
+ end
53
+ end
@@ -591,7 +591,7 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
591
591
  :sanitize_sql_for_assignment, :sanitize_sql_for_conditions, :sanitize_sql_hash,
592
592
  :sanitize_sql_hash_for_assignment, :sanitize_sql_hash_for_conditions,
593
593
  :to_sql, :sanitize, :primary_key, :table_name_prefix, :table_name_suffix,
594
- :where_values_hash, :foreign_key, :uuid
594
+ :where_values_hash, :foreign_key, :uuid, :escape, :escape_string
595
595
  ]
596
596
 
597
597
  def ignore_methods_in_sql
@@ -244,6 +244,10 @@ module Brakeman::Options
244
244
  options[:debug] = true
245
245
  end
246
246
 
247
+ opts.on "--timing", "Measure time for scan steps" do
248
+ options[:show_timing] = true
249
+ end
250
+
247
251
  opts.on "-f",
248
252
  "--format TYPE",
249
253
  [:pdf, :text, :html, :csv, :tabs, :json, :markdown, :codeclimate, :cc, :plain, :table, :junit, :sarif, :sonar, :github],
@@ -529,8 +529,7 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
529
529
 
530
530
  #Process a method definition on self.
531
531
  def process_defs exp
532
- env.scope do
533
- set_env_defaults
532
+ meth_env do
534
533
  exp.body = process_all! exp.body
535
534
  end
536
535
  exp
@@ -84,6 +84,9 @@ module Brakeman::ModuleHelper
84
84
  res.line(exp.line)
85
85
  @current_method = nil
86
86
 
87
+ # TODO: if target is not self/nil, then
88
+ # the method should be added to `target`, not current class
89
+
87
90
  if @current_class
88
91
  @current_class.add_method @visibility, name, res, @current_file
89
92
  elsif @current_module
@@ -96,7 +99,13 @@ module Brakeman::ModuleHelper
96
99
  name = exp.method_name
97
100
 
98
101
  @current_method = name
99
- res = Sexp.new :defn, name, exp.formal_args, *process_all!(exp.body)
102
+
103
+ if @inside_sclass
104
+ res = Sexp.new :defs, s(:self), name, exp.formal_args, *process_all!(exp.body)
105
+ else
106
+ res = Sexp.new :defn, name, exp.formal_args, *process_all!(exp.body)
107
+ end
108
+
100
109
  res.line(exp.line)
101
110
  @current_method = nil
102
111
 
@@ -108,4 +117,25 @@ module Brakeman::ModuleHelper
108
117
 
109
118
  res
110
119
  end
120
+
121
+ # class << self
122
+ def process_sclass exp
123
+ @inside_sclass = true
124
+
125
+ process_all! exp
126
+
127
+ exp
128
+ ensure
129
+ @inside_sclass = false
130
+ end
131
+
132
+ def make_defs exp
133
+ # 'What if' there was some crazy code that had a
134
+ # defs inside a def inside an sclass? :|
135
+ return exp if node_type? exp, :defs
136
+
137
+ raise "Unexpected node type: #{exp.node_type}" unless node_type? exp, :defn
138
+
139
+ Sexp.new(:defs, s(:self), exp.method_name, exp.formal_args, *exp.body).line(exp.line)
140
+ end
111
141
  end
@@ -30,6 +30,12 @@ class Brakeman::LibraryProcessor < Brakeman::BaseProcessor
30
30
  end
31
31
 
32
32
  def process_defn exp
33
+ # TODO: Why is this different from ModuleHelper?
34
+
35
+ if @inside_sclass
36
+ exp = make_defs(exp)
37
+ end
38
+
33
39
  if exp.method_name == :initialize
34
40
  @alias_processor.process_safely exp.body_list
35
41
  @initializer_env = @alias_processor.only_ivars
@@ -30,6 +30,7 @@ class Brakeman::Scanner
30
30
  end
31
31
 
32
32
  @processor = processor || Brakeman::Processor.new(@app_tree, options)
33
+ @show_timing = tracker.options[:debug] || tracker.options[:show_timing]
33
34
  end
34
35
 
35
36
  #Returns the Tracker generated from the scan
@@ -37,35 +38,89 @@ class Brakeman::Scanner
37
38
  @processor.tracked_events
38
39
  end
39
40
 
41
+ def process_step description
42
+ Brakeman.notify "#{description}...".ljust(40)
43
+
44
+ if @show_timing
45
+ start_t = Time.now
46
+ yield
47
+ duration = Time.now - start_t
48
+
49
+ Brakeman.notify "(#{description}) Duration: #{duration} seconds"
50
+ else
51
+ yield
52
+ end
53
+ end
54
+
55
+ def process_step_file description
56
+ if @show_timing
57
+ Brakeman.notify "Processing #{description}"
58
+
59
+ start_t = Time.now
60
+ yield
61
+ duration = Time.now - start_t
62
+
63
+ Brakeman.notify "(#{description}) Duration: #{duration} seconds"
64
+ else
65
+ yield
66
+ end
67
+ end
68
+
40
69
  #Process everything in the Rails application
41
70
  def process
42
- Brakeman.notify "Processing gems... "
43
- process_gems
44
- guess_rails_version
45
- Brakeman.notify "Processing configuration... "
46
- process_config
47
- Brakeman.notify "Parsing files... "
48
- parse_files
49
- Brakeman.notify "Detecting file types... "
50
- detect_file_types
51
- Brakeman.notify "Processing initializers... "
52
- process_initializers
53
- Brakeman.notify "Processing libs... "
54
- process_libs
55
- Brakeman.notify "Processing routes... "
56
- process_routes
57
- Brakeman.notify "Processing templates... "
58
- process_templates
59
- Brakeman.notify "Processing data flow in templates... "
60
- process_template_data_flows
61
- Brakeman.notify "Processing models... "
62
- process_models
63
- Brakeman.notify "Processing controllers... "
64
- process_controllers
65
- Brakeman.notify "Processing data flow in controllers..."
66
- process_controller_data_flows
67
- Brakeman.notify "Indexing call sites... "
68
- index_call_sites
71
+ process_step 'Processing gems' do
72
+ process_gems
73
+ end
74
+
75
+ process_step 'Processing configuration' do
76
+ guess_rails_version
77
+ process_config
78
+ end
79
+
80
+ process_step 'Parsing files' do
81
+ parse_files
82
+ end
83
+
84
+ process_step 'Detecting file types' do
85
+ detect_file_types
86
+ end
87
+
88
+ process_step 'Processing initializers' do
89
+ process_initializers
90
+ end
91
+
92
+ process_step 'Processing libs' do
93
+ process_libs
94
+ end
95
+
96
+ process_step 'Processing routes' do
97
+ process_routes
98
+ end
99
+
100
+ process_step 'Processing templates' do
101
+ process_templates
102
+ end
103
+
104
+ process_step 'Processing data flow in templates' do
105
+ process_template_data_flows
106
+ end
107
+
108
+ process_step 'Processing models' do
109
+ process_models
110
+ end
111
+
112
+ process_step 'Processing controllers' do
113
+ process_controllers
114
+ end
115
+
116
+ process_step 'Processing data flow in controllers' do
117
+ process_controller_data_flows
118
+ end
119
+
120
+ process_step 'Indexing call sites' do
121
+ index_call_sites
122
+ end
123
+
69
124
  tracker
70
125
  end
71
126
 
@@ -214,8 +269,9 @@ class Brakeman::Scanner
214
269
  #Adds parsed information to tracker.initializers
215
270
  def process_initializers
216
271
  track_progress @file_list[:initializers] do |init|
217
- Brakeman.debug "Processing #{init[:path]}"
218
- process_initializer init
272
+ process_step_file init[:path] do
273
+ process_initializer init
274
+ end
219
275
  end
220
276
  end
221
277
 
@@ -234,8 +290,9 @@ class Brakeman::Scanner
234
290
  end
235
291
 
236
292
  track_progress @file_list[:libs] do |lib|
237
- Brakeman.debug "Processing #{lib.path}"
238
- process_lib lib
293
+ process_step_file lib.path do
294
+ process_lib lib
295
+ end
239
296
  end
240
297
  end
241
298
 
@@ -266,8 +323,9 @@ class Brakeman::Scanner
266
323
  #Adds processed controllers to tracker.controllers
267
324
  def process_controllers
268
325
  track_progress @file_list[:controllers] do |controller|
269
- Brakeman.debug "Processing #{controller.path}"
270
- process_controller controller
326
+ process_step_file controller.path do
327
+ process_controller controller
328
+ end
271
329
  end
272
330
  end
273
331
 
@@ -275,9 +333,10 @@ class Brakeman::Scanner
275
333
  controllers = tracker.controllers.sort_by { |name, _| name.to_s }
276
334
 
277
335
  track_progress controllers, "controllers" do |name, controller|
278
- Brakeman.debug "Processing #{name}"
279
- controller.src.each do |file, src|
280
- @processor.process_controller_alias name, src, nil, file
336
+ process_step_file name do
337
+ controller.src.each do |file, src|
338
+ @processor.process_controller_alias name, src, nil, file
339
+ end
281
340
  end
282
341
  end
283
342
 
@@ -300,8 +359,9 @@ class Brakeman::Scanner
300
359
  templates = @file_list[:templates].sort_by { |t| t[:path] }
301
360
 
302
361
  track_progress templates, "templates" do |template|
303
- Brakeman.debug "Processing #{template[:path]}"
304
- process_template template
362
+ process_step_file template[:path] do
363
+ process_template template
364
+ end
305
365
  end
306
366
  end
307
367
 
@@ -313,8 +373,9 @@ class Brakeman::Scanner
313
373
  templates = tracker.templates.sort_by { |name, _| name.to_s }
314
374
 
315
375
  track_progress templates, "templates" do |name, template|
316
- Brakeman.debug "Processing #{name}"
317
- @processor.process_template_alias template
376
+ process_step_file name do
377
+ @processor.process_template_alias template
378
+ end
318
379
  end
319
380
  end
320
381
 
@@ -323,8 +384,9 @@ class Brakeman::Scanner
323
384
  #Adds the processed models to tracker.models
324
385
  def process_models
325
386
  track_progress @file_list[:models] do |model|
326
- Brakeman.debug "Processing #{model[:path]}"
327
- process_model model[:path], model[:ast]
387
+ process_step_file model[:path] do
388
+ process_model model[:path], model[:ast]
389
+ end
328
390
  end
329
391
  end
330
392
 
@@ -120,16 +120,20 @@ module Brakeman
120
120
  filter[:methods] << a[1] if a.node_type == :lit
121
121
  end
122
122
 
123
- if args[-1].node_type == :hash
124
- option = args[-1][1][1]
125
- value = args[-1][2]
126
- case value.node_type
127
- when :array
128
- filter[option] = value.sexp_body.map {|v| v[1] }
129
- when :lit, :str
130
- filter[option] = value[1]
131
- else
132
- Brakeman.debug "[Notice] Unknown before_filter value: #{option} => #{value}"
123
+ options = args.last
124
+
125
+ if hash? options
126
+ # Probably only one option,
127
+ # but this also avoids issues with kwsplats
128
+ hash_iterate(options) do |option, value|
129
+ case value.node_type
130
+ when :array
131
+ filter[option.value] = value.sexp_body.map {|v| v[1] }
132
+ when :lit, :str
133
+ filter[option.value] = value[1]
134
+ else
135
+ Brakeman.debug "[Notice] Unknown before_filter value: #{option} => #{value}"
136
+ end
133
137
  end
134
138
  else
135
139
  filter[:all] = true
@@ -245,7 +245,7 @@ class Brakeman::Tracker
245
245
  end
246
246
 
247
247
  # Not in any included modules, check the parent
248
- @method_cache[cache_key] = find_method(method_name, klass.parent)
248
+ @method_cache[cache_key] = find_method(method_name, klass.parent, method_type)
249
249
  end
250
250
  end
251
251
 
@@ -1,3 +1,3 @@
1
1
  module Brakeman
2
- Version = "6.0.1"
2
+ Version = "6.1.0"
3
3
  end
@@ -130,6 +130,7 @@ module Brakeman::WarningCodes
130
130
  :insecure_rsa_padding_mode => 126,
131
131
  :missing_rsa_padding_mode => 127,
132
132
  :small_rsa_key_size => 128,
133
+ :ransack_search => 129,
133
134
 
134
135
  :custom_check => 9090,
135
136
  }
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: 6.0.1
4
+ version: 6.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Collins
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-20 00:00:00.000000000 Z
11
+ date: 2023-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '3.19'
89
+ version: 3.20.2
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '3.19'
96
+ version: 3.20.2
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: sexp_processor
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -198,6 +198,7 @@ files:
198
198
  - lib/brakeman/checks/check_pathname.rb
199
199
  - lib/brakeman/checks/check_permit_attributes.rb
200
200
  - lib/brakeman/checks/check_quote_table_name.rb
201
+ - lib/brakeman/checks/check_ransack.rb
201
202
  - lib/brakeman/checks/check_redirect.rb
202
203
  - lib/brakeman/checks/check_regex_dos.rb
203
204
  - lib/brakeman/checks/check_render.rb