Read more

Don't mix Array#join and String#html_safe

Henning Koch
January 24, 2011Software engineer at makandra GmbH

You cannot use Array#join on an array of strings where some strings are html_safe and others are not. The result will be an unsafe string and will thus be escaped when rendered in a view:

unsafe_string = '<span>foo</span>'
safe_string = '<span>bar</span>'.html_safe
[unsafe_string, safe_string].join(' ') # will incorrectly render as '&lt;span&gt;foo&lt;/span&gt;&lt;span&t;bar&lt;/span&gt;'

Bad

Illustration money motivation

Opscomplete powered by makandra brand

Save money by migrating from AWS to our fully managed hosting in Germany.

  • Trusted by over 100 customers
  • Ready to use with Ruby, Node.js, PHP
  • Proactive management by operations experts
Read more Show archive.org snapshot

The solution is not to call html_safe on the joined array and if you thought it would be, you don't understand how XSS protection works in Rails. Calling html_safe on the joined array will incorrectly bless the complete string as safe:

[safe_string, unsafe_string].join(' ').html_safe # will incorrectly render as '<span>foo</span><span>bar</span>' with unescaped tags

Good

Rails >=3

safe_join([unsafe_string, safe_string], ' ') # will correctly render as '&lt;span&gt;foo&lt;/span&gt; <span>bar</span>'

Note: The second argument is the separator, that could also be something like content_tag(:br).

If you need to use safe_join() in a model, you need to include ActionView::Helpers::OutputSafetyHelper.

Rails 2

Roll a custom join method that is aware of Rails XSS protection. Copy the following code to config/initializers/xss_aware_join.rb:

Array.class_eval do
  def xss_aware_join(delimiter = '')
    ''.html_safe.tap do |str|
      each_with_index do |element, i|
        str << delimiter if i > 0
        str << element
      end
    end
  end
end

You can now say:

[unsafe_string, safe_string].xss_aware_join(' ') # will correctly render as '&lt;span&gt;foo&lt;/span&gt; <span>bar</span>'
Posted by Henning Koch to makandra dev (2011-01-24 11:12)