ViewComponent::Base#around_render can return HTML-unsafe strings that bypass the escaping behavior applied to normal #call return values. This creates an XSS risk when downstream applications use around_render to wrap, replace, instrument, or conditionally return content that includes user-controlled data.
The issue is especially dangerous in collection rendering because ViewComponent::Collection#render_in joins the per-item results and marks the entire output as html_safe, converting raw unsafe output into a trusted ActiveSupport::SafeBuffer.
Validated against:
eea794453.4.9Relevant locations:
lib/view_component/base.rb
render_inaround_render__vc_maybe_escape_htmllib/view_component/template.rb
InlineCall#safe_method_name_calllib/view_component/collection.rb
Collection#render_inKey code paths:
# lib/view_component/base.rb
around_render do
render_template_for(@__vc_requested_details).to_s
end
# lib/view_component/template.rb
proc do
__vc_maybe_escape_html(send(m)) do
Kernel.warn(...)
end
end
# lib/view_component/collection.rb
components.map do |component|
component.render_in(view_context, &block)
end.join(rendered_spacer(view_context)).html_safe
Normal inline #call output is passed through __vc_maybe_escape_html, which escapes HTML-unsafe strings. However, when around_render itself returns a string, the returned value becomes the component render result without being passed through the same HTML-safety boundary.
This creates two different output-safety behaviors:
#call returning unsafe string: escaped#around_render returning unsafe string: rawCollection rendering then amplifies the issue by calling .html_safe on the joined result.
Run from the repository root:
$LOAD_PATH.unshift File.expand_path("lib", Dir.pwd)
require...
4.12.0Exploitability
AV:NAC:LPR:LUI:RScope
S:CImpact
C:HI:HA:N8.7/CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N