brakeman-min 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 +4 -4
- data/CHANGES.md +13 -0
- data/lib/brakeman/checks/check_pathname.rb +48 -0
- data/lib/brakeman/checks/check_redirect.rb +5 -1
- data/lib/brakeman/checks/check_sanitize_config_cve.rb +1 -1
- data/lib/brakeman/checks/check_weak_rsa_key.rb +112 -0
- data/lib/brakeman/processors/alias_processor.rb +28 -5
- data/lib/brakeman/processors/lib/rails3_config_processor.rb +1 -1
- data/lib/brakeman/report/report_codeclimate.rb +1 -1
- data/lib/brakeman/tracker/config.rb +26 -24
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning_codes.rb +4 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9798eb1c3df5723bd22567e01b13fea359451371d05b8fe9ab173f1f9da07e0d
|
4
|
+
data.tar.gz: 2fd54ab06ad4ce29a4b9bd06938a13c112dc0e7ef977fb79bd80483030e6fb81
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d8ef35740f010db17b501bb6c3057976f027f10956d78eb0bdcf0098b8081f72d467206c65108aa12f7ead44b4fa8d303b08cca259d8594af9364657e7f1a945
|
7
|
+
data.tar.gz: cbbbb5fc955fb107edc0250df0e1ac9f34ac6cccbe623e8f03bfa75a3ec80d3d979d6b8a7f070fe2acdec34a8aa7c6bde62edaaaf47716b415466d40f2597d6a
|
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.
|
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
|
-
|
976
|
-
|
977
|
-
|
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
|
1007
|
-
|
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,
|
89
|
+
@tracker.config.set_rails_config(value: exp.first_arg, path: options_path, overwrite: true)
|
90
90
|
end
|
91
91
|
|
92
92
|
exp
|
@@ -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
|
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]
|
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
|
data/lib/brakeman/version.rb
CHANGED
@@ -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-min
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
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-
|
11
|
+
date: 2022-11-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -209,6 +209,7 @@ files:
|
|
209
209
|
- lib/brakeman/checks/check_nested_attributes_bypass.rb
|
210
210
|
- lib/brakeman/checks/check_number_to_currency.rb
|
211
211
|
- lib/brakeman/checks/check_page_caching_cve.rb
|
212
|
+
- lib/brakeman/checks/check_pathname.rb
|
212
213
|
- lib/brakeman/checks/check_permit_attributes.rb
|
213
214
|
- lib/brakeman/checks/check_quote_table_name.rb
|
214
215
|
- lib/brakeman/checks/check_redirect.rb
|
@@ -247,6 +248,7 @@ files:
|
|
247
248
|
- lib/brakeman/checks/check_validation_regex.rb
|
248
249
|
- lib/brakeman/checks/check_verb_confusion.rb
|
249
250
|
- lib/brakeman/checks/check_weak_hash.rb
|
251
|
+
- lib/brakeman/checks/check_weak_rsa_key.rb
|
250
252
|
- lib/brakeman/checks/check_without_protection.rb
|
251
253
|
- lib/brakeman/checks/check_xml_dos.rb
|
252
254
|
- lib/brakeman/checks/check_yaml_parsing.rb
|
@@ -373,7 +375,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
373
375
|
- !ruby/object:Gem::Version
|
374
376
|
version: '0'
|
375
377
|
requirements: []
|
376
|
-
rubygems_version: 3.1.
|
378
|
+
rubygems_version: 3.1.6
|
377
379
|
signing_key:
|
378
380
|
specification_version: 4
|
379
381
|
summary: Security vulnerability scanner for Ruby on Rails.
|