This occurs on Rails 2.3.10
# this is safe
<% content_for :foo %>
<%= malicious %>
<% end %>"
# this is not safe
<% content_for :foo, malicious %>
The reason is the way ActionPack implements content_for:
def content_for(name, content = nil, &block)
ivar = "@content_for_#{name}"
content = capture(&block) if block_given?
instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{content}".html_safe)
nil
end
Notice it marks the string as html_safe even if it isn't.
Here's the workaround I've come up with, but there may be
something more elegant:
def content_for(name, content = nil, &block)
ivar = "@content_for_#{name}"
content = capture(&block) if block_given?
instance_variable_set(ivar, "#{instance_variable_get(ivar)}#{ERB::Util.h(content)}".html_safe)
nil
end