Mimicking the offical change in Rails 5.1.8 to protect against CVE-2022-32224, all versions of Rails LTS try to use YAML.safe_load
to deserialize database columns in ActiveRecord. This is a potential breaking change.
Background
When using something like
class MyModel < ActiveRecord::Base
serialize :address_data
# or alternatively
store :settings, accessor: [:color, :homepage]
end
ActiveRecord will use YAML to serialize and deserialize data. However, YAML deserialization using YAML.load
(or explicitly YAML.unsafe_load
in newer YAML versions) is dangerous when the persisted data contains malicious content leading to potential Remote Code Execution.
There is no regular known way for an attacker to get this malicious content into the serialized column, however if an attacker manages to get write access to the database through another security issue (like some SQL interpolation bug), they could elevate this attack to a Remote Code Execution, by putting such malicious content into a serialized database column.
Because of this, Rails LTS tries to use YAML.safe_load
where possible, which will only allow deserialization of certain permitted classes. These classes are by default
Symbol
Date
Time
DateTime
ActiveSupport::HashWithIndifferentAccess
ActionDispatch::Http::ParamsHashWithIndifferentAccess
ActionController::Parameters
Note on Ruby 1.8.7 / YAML < 2
If you use Ruby 1.8.7, or you use Ruby < 2.1 and have not added psych
version 2+ to your Gemfile, YAML.safe_load
is not available, and Rails LTS will not be able to protect you against this attack. As noted, this is only a way to escalate another security issue, not a problem in and of itself.
Breaking change
If your code does serialize Ruby classes that are not permitted, reading these classes will cause an exception. You will have to either
- disable the feature altogether, by setting
config.active_record.use_yaml_unsafe_load = true
- or adding the relevant classes using
config.active_record.yaml_column_permitted_classes += ['MyClass']
Do not add classes that might eval
some string upon initialization.
If you are unsure which classes you need to permit, you can either manually check the content of your database columns, or you can temporarily disable the feature and add some in-production tracking Show archive.org snapshot for a while.