brakeman 5.3.1 → 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: 828d560cb256d564c8e79fc7222e7c7edea911639a6c4b45699901371d0c750b
4
- data.tar.gz: c9e8791df7f77b1e6a8d3bfe9cf0f5b753325171021fdafac3531f96edd3b7e1
3
+ metadata.gz: af17bb029ba552f60e4ec332399b3557ed24720b42fe005bd3ae057ff35c69ef
4
+ data.tar.gz: 0b1462edf2d398d503109a5bbb5fd05727bfb6d31af7b052a0eb7b463f31c8ce
5
5
  SHA512:
6
- metadata.gz: 8d29d985cdba9407830c4881372dc4c8ba4cd635c1c48c6cfb16c6fc6b0ef7993816460af301cdf5ca51b096bfdf30699286d6d9fffaae79fff042160b481a87
7
- data.tar.gz: 5d1824dba9dfd9661eccc7ed2a2bb9d2fd1c8d80e131bf0f97ab31cebc738f920682fe7204a8b84ee49c884c8730c2425ef20bd15f2b53c3ada1a2332d75779e
6
+ metadata.gz: 4ca3b2e7a76d69ef82bc451dba3383da830e89700565aaa38d0955a2566a15ee1a5e94e5d4e8c98dbb95a5083c97a000030361c2628ad6d39a02f178491eeeff
7
+ data.tar.gz: 6f0b414997abd0aed5bf511680cfc4e33916d18eca44b1505dec0b4d61c8b3ff566564b3c61f2c6952cd619f20f6d5069e268229394db3afd6c731350fdd26a2
data/CHANGES.md CHANGED
@@ -1,3 +1,12 @@
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
+
1
10
  # 5.3.1 - 2022-08-09
2
11
 
3
12
  * Fix version range for CVE-2022-32209
@@ -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
@@ -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.1"
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
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.3.1
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
  description: Brakeman detects security vulnerabilities in Ruby on Rails applications
14
14
  via static analysis.
@@ -482,6 +482,7 @@ files:
482
482
  - lib/brakeman/checks/check_nested_attributes_bypass.rb
483
483
  - lib/brakeman/checks/check_number_to_currency.rb
484
484
  - lib/brakeman/checks/check_page_caching_cve.rb
485
+ - lib/brakeman/checks/check_pathname.rb
485
486
  - lib/brakeman/checks/check_permit_attributes.rb
486
487
  - lib/brakeman/checks/check_quote_table_name.rb
487
488
  - lib/brakeman/checks/check_redirect.rb
@@ -520,6 +521,7 @@ files:
520
521
  - lib/brakeman/checks/check_validation_regex.rb
521
522
  - lib/brakeman/checks/check_verb_confusion.rb
522
523
  - lib/brakeman/checks/check_weak_hash.rb
524
+ - lib/brakeman/checks/check_weak_rsa_key.rb
523
525
  - lib/brakeman/checks/check_without_protection.rb
524
526
  - lib/brakeman/checks/check_xml_dos.rb
525
527
  - lib/brakeman/checks/check_yaml_parsing.rb
@@ -646,7 +648,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
646
648
  - !ruby/object:Gem::Version
647
649
  version: '0'
648
650
  requirements: []
649
- rubygems_version: 3.1.2
651
+ rubygems_version: 3.1.6
650
652
  signing_key:
651
653
  specification_version: 4
652
654
  summary: Security vulnerability scanner for Ruby on Rails.