brakeman-lib 5.3.0 → 5.4.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: df75ab4f9b0d2b0ed8db5548e0f18e8fc7028b9ed19e3b05e583e62070aac6d3
4
- data.tar.gz: 1af6b8a2ecd4286a7808b357779cfbd720bb263a371ca86fd9555bf806e97d01
3
+ metadata.gz: c63376837c6212df7e6f9ec337cc1091bcb726799b2437293cd6a32cbc59362a
4
+ data.tar.gz: 5c3023810d965759ce42f96ce1af3a5de5dd891b907f7d50c8ce1c1aa0e058ca
5
5
  SHA512:
6
- metadata.gz: 32b3f95690c33c05aced581c94c60544c8b4d02ec85e001d2a67f54eedaad15f9bd52157d526d6ab3cc9d30f33fc07c155e6030cd6d75f8cac5b5ff82739daa1
7
- data.tar.gz: 55ff958c1101ac534921807d105253c65b3ef62500b1354dacd42d922ac6f8ce446db1213398f95d80d87f8af47a4c430e3d38f13592aeaeadfa156b9f347a82
6
+ metadata.gz: f7e7972da6fb0625832a35c8faf224df3de41dab66a1986110f671c21b5609262697656045e67ca418665aa9d5638ff8ff42a293e01f16406b54de718ce38da5
7
+ data.tar.gz: f43ea6ec1fb403926d3e5c021f94a18babb611bc53c3ad073e9af25ac40c49aeeefd630460f43fb8c45d08be18754a2d0270fad8e70fda2d0089674e29f6ec7c
data/CHANGES.md CHANGED
@@ -1,3 +1,16 @@
1
+ # 5.4.0 - 2022-11-17
2
+
3
+ * Use relative paths for CodeClimate report format (Mike Poage)
4
+ * Add check for weak RSA key sizes and padding modes
5
+ * Handle multiple values and splats in case/when
6
+ * Ignore more model methods in redirects
7
+ * Add check for absolute paths issue with Pathname
8
+ * Fix `load_rails_defaults` overwriting settings in the Rails application (James Gregory-Monk)
9
+
10
+ # 5.3.1 - 2022-08-09
11
+
12
+ * Fix version range for CVE-2022-32209
13
+
1
14
  # 5.3.0 - 2022-08-09
2
15
 
3
16
  * Include explicit engine or lib paths in vendor/ (Joe Rafaniello)
@@ -0,0 +1,48 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckPathname < Brakeman::BaseCheck
4
+ Brakeman::Checks.add self
5
+
6
+ @description = "Check for unexpected Pathname behavior"
7
+
8
+ def run_check
9
+ check_rails_root_join
10
+ check_pathname_join
11
+
12
+ end
13
+
14
+ def check_rails_root_join
15
+ tracker.find_call(target: :'Rails.root', method: :join, nested: true).each do |result|
16
+ check_result result
17
+ end
18
+ end
19
+
20
+ def check_pathname_join
21
+ pathname_methods = [
22
+ :'Pathname.new',
23
+ :'Pathname.getwd',
24
+ :'Pathname.glob',
25
+ :'Pathname.pwd',
26
+ ]
27
+
28
+ tracker.find_call(targets: pathname_methods, method: :join, nested: true).each do |result|
29
+ check_result result
30
+ end
31
+ end
32
+
33
+ def check_result result
34
+ return unless original? result
35
+
36
+ result[:call].each_arg do |arg|
37
+ if match = has_immediate_user_input?(arg)
38
+ warn :result => result,
39
+ :warning_type => "Path Traversal",
40
+ :warning_code => :pathname_traversal,
41
+ :message => "Absolute paths in `Pathname#join` cause the entire path to be relative to the absolute path, ignoring any prior values",
42
+ :user_input => match,
43
+ :confidence => :high,
44
+ :cwe_id => [22]
45
+ end
46
+ end
47
+ end
48
+ end
@@ -13,7 +13,7 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
13
13
  def run_check
14
14
  Brakeman.debug "Finding calls to redirect_to()"
15
15
 
16
- @model_find_calls = Set[:all, :create, :create!, :find, :find_by_sql, :first, :last, :new]
16
+ @model_find_calls = Set[:all, :create, :create!, :find, :find_by_sql, :first, :first!, :last, :last!, :new, :sole]
17
17
 
18
18
  if tracker.options[:rails3]
19
19
  @model_find_calls.merge [:from, :group, :having, :joins, :lock, :order, :reorder, :select, :where]
@@ -23,6 +23,10 @@ class Brakeman::CheckRedirect < Brakeman::BaseCheck
23
23
  @model_find_calls.merge [:find_by, :find_by!, :take]
24
24
  end
25
25
 
26
+ if version_between? "7.0.0", "9.9.9"
27
+ @model_find_calls << :find_sole_by
28
+ end
29
+
26
30
  @tracker.find_call(:target => false, :method => :redirect_to).each do |res|
27
31
  process_result res
28
32
  end
@@ -9,7 +9,7 @@ class Brakeman::CheckSanitizeConfigCve < Brakeman::BaseCheck
9
9
  @specific_warning = false
10
10
 
11
11
  @gem_version = tracker.config.gem_version :'rails-html-sanitizer'
12
- if version_between? "0.0.0", "1.4.3", @gem_version
12
+ if version_between? "0.0.0", "1.4.2", @gem_version
13
13
  check_config
14
14
  check_sanitize_calls
15
15
  check_safe_list_allowed_tags
@@ -0,0 +1,112 @@
1
+ require 'brakeman/checks/base_check'
2
+
3
+ class Brakeman::CheckWeakRSAKey < Brakeman::BaseCheck
4
+ Brakeman::Checks.add self
5
+
6
+ @description = "Checks for weak uses RSA keys"
7
+
8
+ def run_check
9
+ check_rsa_key_creation
10
+ check_rsa_operations
11
+ end
12
+
13
+ def check_rsa_key_creation
14
+ tracker.find_call(targets: [:'OpenSSL::PKey::RSA'], method: [:new, :generate], nested: true).each do |result|
15
+ key_size_arg = result[:call].first_arg
16
+ check_key_size(result, key_size_arg)
17
+ end
18
+
19
+ tracker.find_call(targets: [:'OpenSSL::PKey'], method: [:generate_key], nested: true).each do |result|
20
+ call = result[:call]
21
+ key_type = call.first_arg
22
+ options_arg = call.second_arg
23
+
24
+ next unless options_arg and hash? options_arg
25
+
26
+ if string? key_type and key_type.value.upcase == 'RSA'
27
+ key_size_arg = (hash_access(options_arg, :rsa_keygen_bits) || hash_access(options_arg, s(:str, 'rsa_key_gen_bits')))
28
+ check_key_size(result, key_size_arg)
29
+ end
30
+ end
31
+ end
32
+
33
+ def check_rsa_operations
34
+ tracker.find_call(targets: [:'OpenSSL::PKey::RSA.new'], methods: [:public_encrypt, :public_decrypt, :private_encrypt, :private_decrypt], nested: true).each do |result|
35
+ padding_arg = result[:call].second_arg
36
+ check_padding(result, padding_arg)
37
+ end
38
+
39
+ tracker.find_call(targets: [:'OpenSSL::PKey.generate_key'], methods: [:encrypt, :decrypt, :sign, :verify, :sign_raw, :verify_raw], nested: true).each do |result|
40
+ call = result[:call]
41
+ options_arg = call.last_arg
42
+
43
+ if options_arg and hash? options_arg
44
+ padding_arg = (hash_access(options_arg, :rsa_padding_mode) || hash_access(options_arg, s(:str, 'rsa_padding_mode')))
45
+ else
46
+ padding_arg = nil
47
+ end
48
+
49
+ check_padding(result, padding_arg)
50
+ end
51
+ end
52
+
53
+ def check_key_size result, key_size_arg
54
+ return unless number? key_size_arg
55
+ return unless original? result
56
+
57
+ key_size = key_size_arg.value
58
+
59
+ if key_size < 1024
60
+ confidence = :high
61
+ message = msg("RSA key with size ", msg_code(key_size.to_s), " is considered very weak. Use at least 2048 bit key size")
62
+ elsif key_size < 2048
63
+ confidence = :medium
64
+ message = msg("RSA key with size ", msg_code(key_size.to_s), " is considered weak. Use at least 2048 bit key size")
65
+ else
66
+ return
67
+ end
68
+
69
+ warn result: result,
70
+ warning_type: "Weak Cryptography",
71
+ warning_code: :small_rsa_key_size,
72
+ message: message,
73
+ confidence: confidence,
74
+ user_input: key_size_arg,
75
+ cwe_id: [326]
76
+ end
77
+
78
+ PKCS1_PADDING = s(:colon2, s(:colon2, s(:colon2, s(:const, :OpenSSL), :PKey), :RSA), :PKCS1_PADDING).freeze
79
+ PKCS1_PADDING_STR = s(:str, 'pkcs1').freeze
80
+ SSLV23_PADDING = s(:colon2, s(:colon2, s(:colon2, s(:const, :OpenSSL), :PKey), :RSA), :SSLV23_PADDING).freeze
81
+ SSLV23_PADDING_STR = s(:str, 'sslv23').freeze
82
+ NO_PADDING = s(:colon2, s(:colon2, s(:colon2, s(:const, :OpenSSL), :PKey), :RSA), :NO_PADDING).freeze
83
+ NO_PADDING_STR = s(:str, 'none').freeze
84
+
85
+ def check_padding result, padding_arg
86
+ return unless original? result
87
+
88
+ if string? padding_arg
89
+ padding_arg = padding_arg.deep_clone(padding_arg.line)
90
+ padding_arg.value.downcase!
91
+ end
92
+
93
+ case padding_arg
94
+ when PKCS1_PADDING, PKCS1_PADDING_STR, nil
95
+ message = "Use of padding mode PKCS1 (default if not specified), which is known to be insecure. Use OAEP instead"
96
+ when SSLV23_PADDING, SSLV23_PADDING_STR
97
+ message = "Use of padding mode SSLV23 for RSA key, which is only useful for outdated versions of SSL. Use OAEP instead"
98
+ when NO_PADDING, NO_PADDING_STR
99
+ message = "No padding mode used for RSA key. A safe padding mode (OAEP) should be specified for RSA keys"
100
+ else
101
+ return
102
+ end
103
+
104
+ warn result: result,
105
+ warning_type: "Weak Cryptography",
106
+ warning_code: :insecure_rsa_padding_mode,
107
+ message: message,
108
+ confidence: :high,
109
+ user_input: padding_arg,
110
+ cwe_id: [780]
111
+ end
112
+ end
@@ -970,11 +970,27 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
970
970
  exp.method == :==
971
971
  end
972
972
 
973
+ # Not a list of values
974
+ # when :example
973
975
  def simple_when? exp
974
976
  node_type? exp[1], :array and
975
- not node_type? exp[1][1], :splat, :array and
976
- (exp[1].length == 2 or
977
- exp[1].all? { |e| e.is_a? Symbol or node_type? e, :lit, :str })
977
+ exp[1].length == 2 and # only one element in the array
978
+ not node_type? exp[1][1], :splat, :array
979
+ end
980
+
981
+ # A list of literal values
982
+ #
983
+ # when 1,2,3
984
+ #
985
+ # or
986
+ #
987
+ # when *[:a, :b]
988
+ def all_literals_when? exp
989
+ if array? exp[1] # pretty sure this is always true
990
+ all_literals? exp[1] or # simple list, not actually array
991
+ (splat_array? exp[1][1] and
992
+ all_literals? exp[1][1][1])
993
+ end
978
994
  end
979
995
 
980
996
  def process_case exp
@@ -1002,9 +1018,16 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
1002
1018
  scope do
1003
1019
  @branch_env = env.current
1004
1020
 
1021
+ # Process the when value for matching
1022
+ process_default e[1]
1023
+
1005
1024
  # set value of case var if possible
1006
- if case_value and simple_when? e
1007
- @branch_env[case_value] = e[1][1]
1025
+ if case_value
1026
+ if simple_when? e
1027
+ @branch_env[case_value] = e[1][1]
1028
+ elsif all_literals_when? e
1029
+ @branch_env[case_value] = safe_literal(e.line + 1)
1030
+ end
1008
1031
  end
1009
1032
 
1010
1033
  # when blocks aren't blocks, they are lists of expressions
@@ -86,7 +86,7 @@ class Brakeman::Rails3ConfigProcessor < Brakeman::BasicProcessor
86
86
  end
87
87
  elsif include_rails_config? exp
88
88
  options_path = get_rails_config exp
89
- @tracker.config.set_rails_config(exp.first_arg, *options_path)
89
+ @tracker.config.set_rails_config(value: exp.first_arg, path: options_path, overwrite: true)
90
90
  end
91
91
 
92
92
  exp
@@ -73,7 +73,7 @@ class Brakeman::Report::CodeClimate < Brakeman::Report::Base
73
73
  if tracker.options[:path_prefix]
74
74
  (Pathname.new(tracker.options[:path_prefix]) + Pathname.new(warning.file.relative)).to_s
75
75
  else
76
- warning.file
76
+ warning.relative_path
77
77
  end
78
78
  end
79
79
  end
@@ -166,7 +166,7 @@ module Brakeman
166
166
  # then this will set
167
167
  #
168
168
  # rails[:action_controller][:perform_caching] = value
169
- def set_rails_config value, *path
169
+ def set_rails_config value:, path:, overwrite: false
170
170
  config = self.rails
171
171
 
172
172
  path[0..-2].each do |o|
@@ -182,7 +182,9 @@ module Brakeman
182
182
  config = option
183
183
  end
184
184
 
185
- config[path.last] = value
185
+ if overwrite || config[path.last].nil?
186
+ config[path.last] = value
187
+ end
186
188
  end
187
189
 
188
190
  # Load defaults based on config.load_defaults value
@@ -195,38 +197,38 @@ module Brakeman
195
197
  false_value = Sexp.new(:false)
196
198
 
197
199
  if version >= 5.0
198
- set_rails_config(true_value, :action_controller, :per_form_csrf_tokens)
199
- set_rails_config(true_value, :action_controller, :forgery_protection_origin_check)
200
- set_rails_config(true_value, :active_record, :belongs_to_required_by_default)
200
+ set_rails_config(value: true_value, path: [:action_controller, :per_form_csrf_tokens])
201
+ set_rails_config(value: true_value, path: [:action_controller, :forgery_protection_origin_check])
202
+ set_rails_config(value: true_value, path: [:active_record, :belongs_to_required_by_default])
201
203
  # Note: this may need to be changed, because ssl_options is a Hash
202
- set_rails_config(true_value, :ssl_options, :hsts, :subdomains)
204
+ set_rails_config(value: true_value, path: [:ssl_options, :hsts, :subdomains])
203
205
  end
204
206
 
205
207
  if version >= 5.1
206
- set_rails_config(false_value, :assets, :unknown_asset_fallback)
207
- set_rails_config(true_value, :action_view, :form_with_generates_remote_forms)
208
+ set_rails_config(value: false_value, path: [:assets, :unknown_asset_fallback])
209
+ set_rails_config(value: true_value, path: [:action_view, :form_with_generates_remote_forms])
208
210
  end
209
211
 
210
212
  if version >= 5.2
211
- set_rails_config(true_value, :active_record, :cache_versioning)
212
- set_rails_config(true_value, :action_dispatch, :use_authenticated_cookie_encryption)
213
- set_rails_config(true_value, :active_support, :use_authenticated_message_encryption)
214
- set_rails_config(true_value, :active_support, :use_sha1_digests)
215
- set_rails_config(true_value, :action_controller, :default_protect_from_forgery)
216
- set_rails_config(true_value, :action_view, :form_with_generates_ids)
213
+ set_rails_config(value: true_value, path: [:active_record, :cache_versioning])
214
+ set_rails_config(value: true_value, path: [:action_dispatch, :use_authenticated_cookie_encryption])
215
+ set_rails_config(value: true_value, path: [:active_support, :use_authenticated_message_encryption])
216
+ set_rails_config(value: true_value, path: [:active_support, :use_sha1_digests])
217
+ set_rails_config(value: true_value, path: [:action_controller, :default_protect_from_forgery])
218
+ set_rails_config(value: true_value, path: [:action_view, :form_with_generates_ids])
217
219
  end
218
220
 
219
221
  if version >= 6.0
220
- set_rails_config(Sexp.new(:lit, :zeitwerk), :autoloader)
221
- set_rails_config(false_value, :action_view, :default_enforce_utf8)
222
- set_rails_config(true_value, :action_dispatch, :use_cookies_with_metadata)
223
- set_rails_config(false_value, :action_dispatch, :return_only_media_type_on_content_type)
224
- set_rails_config(Sexp.new(:str, 'ActionMailer::MailDeliveryJob'), :action_mailer, :delivery_job)
225
- set_rails_config(true_value, :active_job, :return_false_on_aborted_enqueue)
226
- set_rails_config(Sexp.new(:lit, :active_storage_analysis), :active_storage, :queues, :analysis)
227
- set_rails_config(Sexp.new(:lit, :active_storage_purge), :active_storage, :queues, :purge)
228
- set_rails_config(true_value, :active_storage, :replace_on_assign_to_many)
229
- set_rails_config(true_value, :active_record, :collection_cache_versioning)
222
+ set_rails_config(value: Sexp.new(:lit, :zeitwerk), path: [:autoloader])
223
+ set_rails_config(value: false_value, path: [:action_view, :default_enforce_utf8])
224
+ set_rails_config(value: true_value, path: [:action_dispatch, :use_cookies_with_metadata])
225
+ set_rails_config(value: false_value, path: [:action_dispatch, :return_only_media_type_on_content_type])
226
+ set_rails_config(value: Sexp.new(:str, 'ActionMailer::MailDeliveryJob'), path: [:action_mailer, :delivery_job])
227
+ set_rails_config(value: true_value, path: [:active_job, :return_false_on_aborted_enqueue])
228
+ set_rails_config(value: Sexp.new(:lit, :active_storage_analysis), path: [:active_storage, :queues, :analysis])
229
+ set_rails_config(value: Sexp.new(:lit, :active_storage_purge), path: [:active_storage, :queues, :purge])
230
+ set_rails_config(value: true_value, path: [:active_storage, :replace_on_assign_to_many])
231
+ set_rails_config(value: true_value, path: [:active_record, :collection_cache_versioning])
230
232
  end
231
233
  end
232
234
  end
@@ -1,3 +1,3 @@
1
1
  module Brakeman
2
- Version = "5.3.0"
2
+ Version = "5.4.0"
3
3
  end
@@ -126,6 +126,10 @@ module Brakeman::WarningCodes
126
126
  :pending_eol_rails => 122,
127
127
  :pending_eol_ruby => 123,
128
128
  :CVE_2022_32209 => 124,
129
+ :pathname_traversal => 125,
130
+ :insecure_rsa_padding_mode => 126,
131
+ :missing_rsa_padding_mode => 127,
132
+ :small_rsa_key_size => 128,
129
133
 
130
134
  :custom_check => 9090,
131
135
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brakeman-lib
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.3.0
4
+ version: 5.4.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: 2022-08-10 00:00:00.000000000 Z
11
+ date: 2022-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -299,6 +299,7 @@ files:
299
299
  - lib/brakeman/checks/check_nested_attributes_bypass.rb
300
300
  - lib/brakeman/checks/check_number_to_currency.rb
301
301
  - lib/brakeman/checks/check_page_caching_cve.rb
302
+ - lib/brakeman/checks/check_pathname.rb
302
303
  - lib/brakeman/checks/check_permit_attributes.rb
303
304
  - lib/brakeman/checks/check_quote_table_name.rb
304
305
  - lib/brakeman/checks/check_redirect.rb
@@ -337,6 +338,7 @@ files:
337
338
  - lib/brakeman/checks/check_validation_regex.rb
338
339
  - lib/brakeman/checks/check_verb_confusion.rb
339
340
  - lib/brakeman/checks/check_weak_hash.rb
341
+ - lib/brakeman/checks/check_weak_rsa_key.rb
340
342
  - lib/brakeman/checks/check_without_protection.rb
341
343
  - lib/brakeman/checks/check_xml_dos.rb
342
344
  - lib/brakeman/checks/check_yaml_parsing.rb
@@ -463,7 +465,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
463
465
  - !ruby/object:Gem::Version
464
466
  version: '0'
465
467
  requirements: []
466
- rubygems_version: 3.1.2
468
+ rubygems_version: 3.1.6
467
469
  signing_key:
468
470
  specification_version: 4
469
471
  summary: Security vulnerability scanner for Ruby on Rails.