Ensure YAML safe loading in Rails 6.1
As part of the fix for CVE-2022-32224 Rails intruduced safe YAML loading and the `ActiveRecord.yaml_column_permitted_classes` config. PaperTrail added support for respecting the new configuration here https://github.com/paper-trail-gem/paper_trail/pull/1397 The CVE-2022-32224 fix was also backported to Rails versions 5.2.8.1, 6.0.5.1, and, 6.1.6.1, however the name of the confiuration is slightly different from that in Rails 7.x. 7.0.3.1 ActiveRecord.yaml_column_permitted_classes 6.1.6.1 ActiveRecord::Base.yaml_column_permitted_classes 6.0.5.1 ActiveRecord::Base.yaml_column_permitted_classes 5.2.8.1 ActiveRecord::Base.yaml_column_permitted_classes PaperTrail currently doesn't support this alternative configuration naming, which means it will silent fall back to unsafe YAML loading. This commit updates `PaperTrail::Serializers::YAML` to be compatible with safe YAML loading for the Rails 5.2 / 6.0 / 6.1 branches.
This commit is contained in:
parent
e71c65604f
commit
172ac1d747
|
@ -12,7 +12,7 @@ module PaperTrail
|
|||
if use_safe_load?
|
||||
::YAML.safe_load(
|
||||
string,
|
||||
permitted_classes: ::ActiveRecord.yaml_column_permitted_classes,
|
||||
permitted_classes: yaml_column_permitted_classes,
|
||||
aliases: true
|
||||
)
|
||||
elsif ::YAML.respond_to?(:unsafe_load)
|
||||
|
@ -39,10 +39,28 @@ module PaperTrail
|
|||
|
||||
private
|
||||
|
||||
# `use_yaml_unsafe_load` was added in 7.0.3.1, will be removed in 7.1.0?
|
||||
def use_safe_load?
|
||||
defined?(ActiveRecord.use_yaml_unsafe_load) &&
|
||||
!ActiveRecord.use_yaml_unsafe_load
|
||||
if ::ActiveRecord.gem_version >= Gem::Version.new("7.0.3.1")
|
||||
# `use_yaml_unsafe_load` may be removed in the future, at which point safe loading will be
|
||||
# the default.
|
||||
!defined?(ActiveRecord.use_yaml_unsafe_load) || !ActiveRecord.use_yaml_unsafe_load
|
||||
elsif defined?(ActiveRecord::Base.use_yaml_unsafe_load)
|
||||
# Rails 5.2.8.1, 6.0.5.1, 6.1.6.1
|
||||
!ActiveRecord::Base.use_yaml_unsafe_load
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def yaml_column_permitted_classes
|
||||
if ::ActiveRecord.gem_version >= Gem::Version.new("7.0.3.1")
|
||||
ActiveRecord.yaml_column_permitted_classes
|
||||
elsif defined?(ActiveRecord::Base.yaml_column_permitted_classes)
|
||||
# Rails 5.2.8.1, 6.0.5.1, 6.1.6.1
|
||||
ActiveRecord::Base.yaml_column_permitted_classes
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,7 +13,17 @@ require File.expand_path("boot", __dir__)
|
|||
|
||||
module Dummy
|
||||
class Application < Rails::Application
|
||||
config.load_defaults(::Rails.gem_version.segments.take(2).join("."))
|
||||
YAML_COLUMN_PERMITTED_CLASSES = [
|
||||
::ActiveRecord::Type::Time::Value,
|
||||
::ActiveSupport::TimeWithZone,
|
||||
::ActiveSupport::TimeZone,
|
||||
::BigDecimal,
|
||||
::Date,
|
||||
::Symbol,
|
||||
::Time
|
||||
].freeze
|
||||
|
||||
config.load_defaults(::ActiveRecord.gem_version.segments.take(2).join("."))
|
||||
|
||||
config.encoding = "utf-8"
|
||||
config.filter_parameters += [:password]
|
||||
|
@ -21,18 +31,13 @@ module Dummy
|
|||
config.active_support.test_order = :sorted
|
||||
config.secret_key_base = "A fox regularly kicked the screaming pile of biscuits."
|
||||
|
||||
# `use_yaml_unsafe_load` was added in 7.0.3.1, will be removed in 7.1.0?
|
||||
if ::ActiveRecord.respond_to?(:use_yaml_unsafe_load)
|
||||
# `use_yaml_unsafe_load` was added in 5.2.8.1, 6.0.5.1, 6.1.6.1, and 7.0.3.1
|
||||
if ::ActiveRecord.gem_version >= Gem::Version.new("7.0.3.1")
|
||||
::ActiveRecord.use_yaml_unsafe_load = false
|
||||
::ActiveRecord.yaml_column_permitted_classes = [
|
||||
::ActiveRecord::Type::Time::Value,
|
||||
::ActiveSupport::TimeWithZone,
|
||||
::ActiveSupport::TimeZone,
|
||||
::BigDecimal,
|
||||
::Date,
|
||||
::Symbol,
|
||||
::Time
|
||||
]
|
||||
::ActiveRecord.yaml_column_permitted_classes = YAML_COLUMN_PERMITTED_CLASSES
|
||||
elsif ::ActiveRecord::Base.respond_to?(:use_yaml_unsafe_load)
|
||||
::ActiveRecord::Base.use_yaml_unsafe_load = false
|
||||
::ActiveRecord::Base.yaml_column_permitted_classes = YAML_COLUMN_PERMITTED_CLASSES
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -24,12 +24,12 @@ module PaperTrail
|
|||
end
|
||||
|
||||
it "calls the expected load method based on Psych version" do
|
||||
# `use_yaml_unsafe_load` was added in 7.0.3.1, will be removed in 7.1.0?
|
||||
if defined?(ActiveRecord.use_yaml_unsafe_load) && !ActiveRecord.use_yaml_unsafe_load
|
||||
# `use_yaml_unsafe_load` was added in 5.2.8.1, 6.0.5.1, 6.1.6.1, and 7.0.3.1
|
||||
if rails_supports_safe_load?
|
||||
allow(::YAML).to receive(:safe_load)
|
||||
described_class.load("string")
|
||||
expect(::YAML).to have_received(:safe_load)
|
||||
# Psych 4+ implements .unsafe_load
|
||||
# Psych 4+ implements .unsafe_load
|
||||
elsif ::YAML.respond_to?(:unsafe_load)
|
||||
allow(::YAML).to receive(:unsafe_load)
|
||||
described_class.load("string")
|
||||
|
@ -60,6 +60,16 @@ module PaperTrail
|
|||
expect(arel_value(matches.right)).to eq("%\narg1: Val 1\n%")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def rails_supports_safe_load?
|
||||
# Rails 7.0.3.1 onwards will always support YAML safe loading
|
||||
return true if ::ActiveRecord.gem_version >= Gem::Version.new("7.0.3.1")
|
||||
|
||||
# Older Rails versions may or may not, depending on whether they have been patched.
|
||||
defined?(ActiveRecord::Base.use_yaml_unsafe_load)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue