28 cards
Posted 6 days ago. Visible to the public.

Change to ActiveRecord deserialization (CVE-2022-32224)

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

Copy
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

Copy
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 Archive for a while.

Growing Rails Applications in Practice
Check out our new e-book:
Learn to structure large Ruby on Rails codebases with the tools you already know and love.

Owner of this card:

Avatar
Tobias Kraze
Last edit:
6 days ago
by Tobias Kraze
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
This website uses short-lived cookies to improve usability.
Accept or learn more