Posted over 9 years ago. Visible to the public. Repeats.

Don't mix Array#join and String#html_safe

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;'


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


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).

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>'

Once an application no longer requires constant development, it needs periodic maintenance for stable and secure operation. makandra offers monthly maintenance contracts that let you focus on your business while we make sure the lights stay on.

Owner of this card:

Henning Koch
Last edit:
12 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
Posted by Henning Koch to makandra dev
This website uses cookies to improve usability and analyze traffic.
Accept or learn more