GHSA-2w9f-fxwj-w2qf: Active Support: Possible XSS vulnerability in Active Support MessagePack serializer
Impact ActiveSupport::MessagePack serializes an ActiveSupport::SafeBuffer as its bytes alone and deserializes it as a new SafeBuffer, so a buffer that is no longer htmlsafe? (for example, one mutated in place with gsub!) is restored as htmlsafe. If such a buffer holds untrusted input and is stored through a MessagePack serializer, rendering it after it is loaded bypasses ERB auto-escaping, possibly leading to XSS.
Applications on Rails 8.1 are affected if they use a MessagePack serializer, such as config.actiondispatch.cookiesserializer = :messagepack or :messagepackallowmarshal, or serializer: :messagepack for Rails.cache, ActiveSupport::MessageVerifier or ActiveSupport::MessageEncryptor, and store a SafeBuffer that was mutated in place with untrusted input. Rails 8.0 and earlier do not serialize SafeBuffer with MessagePack and are not affected.
Details The fixed releases serialize a SafeBuffer that is not htmlsafe? with a marker and deserialize it as a String; a SafeBuffer that is htmlsafe? keeps the existing format. Versions without the fix cannot read an unsafe buffer serialized by the fixed releases, so during a rolling deploy a cookie or cache entry holding one could fail to load on a process that has not been upgraded.
Workarounds Applications that cannot upgrade can convert a SafeBuffer to a String with tostr before storing it in a value that a MessagePack serializer writes.
Releases The fixed releases are available at the normal locations.
Patches for those who cannot upgrade at once: - 8.1: https://github.com/rails/rails/commit/4ca090665976e6fbc471c38689b399f84b43cdc7.patch
Credit This issue was responsibly reported by HackerOne researcher jcwilk.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
rubygems/activesupportto a version that resolves this vulnerability.Fixed in 8.1.4.1 - Upgrade
Upgrade
Railsto a version that resolves this vulnerability.Patch 4ca090665976e6fbc471c38689b399f84b43cdc7 - Compensating control
If upgrading is not immediately possible, convert any SafeBuffer to a String with to_str before storing it in a value written by a MessagePack serializer.
Event History
Frequently Asked Questions
Which Rails deployments are exposed?
Rails 8.1 applications are affected only when they use a MessagePack serializer and persist an ActiveSupport::SafeBuffer that has been mutated in place with untrusted input. Rails 8.0 and earlier are not affected because they do not serialize SafeBuffer with MessagePack.
Which MessagePack uses should be reviewed?
Review cookies configured with config.action_dispatch.cookies_serializer = :message_pack or :message_pack_allow_marshal. Also review Rails.cache, ActiveSupport::MessageVerifier, and ActiveSupport::MessageEncryptor when configured with serializer: :message_pack.
What conditions are needed for exploitation?
An attacker-controlled value must end up in a SafeBuffer that is made unsafe by an in-place mutation such as gsub!, then be stored and later loaded through a MessagePack serializer. The application must subsequently render that restored value in a context where ERB auto-escaping would otherwise be relied upon.
What should be considered during a rolling upgrade?
Older, unfixed versions cannot read an unsafe buffer serialized by a fixed release. Mixed fixed and unfixed instances may therefore have serialization compatibility issues during a rolling deployment.