Skip to content

Instantly share code, notes, and snippets.

@mieko
Created October 14, 2020 03:03
Show Gist options
  • Save mieko/5f40fcf42ca95150023c2c627d3272d8 to your computer and use it in GitHub Desktop.
Save mieko/5f40fcf42ca95150023c2c627d3272d8 to your computer and use it in GitHub Desktop.
Mixed HTML/Plaintext `flash` messages in Rails 4.1+ JSON cookie serializer
require "rack/utils"
# Rails < 4.1 serialized sessions with Marshal, which could distinguish "html_safe" flash strings
# from unsafe strings because it encoded actual ActiveSupport::SafeBuffer objects. So when the
# flash message came back from the client, its "safe" status was preserved, and it was rendered
# correctly under both circumstances.
#
# This same "magic" ability is also why Rails moved away from it: multiple CVEs due to arbitrary
# object creation. But regardless, that was a *really* nice trick.
#
# The JSON encoder cannot discriminate between safe and unsafe strings: they're all just strings
# when they come back. So we now have to commit to rendering all flash messages as either
# plain-text or HTML at render time.
#
# This mixin HTML-escapes values assigned to `flash` keys on assignment, but does not escape
# objects which are `html_safe?`. This means we'll get escaped output by default (so we're still
# XSS-safe), but can override it when we need to use HTML in flash messages (via `#html_safe` on
# the string), much like the old Marshal serializer.
#
# So rendering flash notices in the layout as un-escaped is now safe, and does what we want again.
module SanitizedFlash
def []=(key, value)
super(key, value.html_safe? ? value : Rack::Utils.escape_html(value.to_s))
end
end
ActionDispatch::Flash::FlashHash.prepend(::SanitizedFlash)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment