GitHub Advisoryadvisory · RubyGems

GHSA-97jw-64cj-jc58 ViewComponent: around_render HTML-Safety Bypass

HIGH Published 2026-07-15 Modified 2026-07-15 Official page ↗
Aliases
CVE-2026-54498
Ecosystem
RubyGems
Packages
view_component
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N
Weaknesses
CWE-79
Reviewed
2026-07-15

Affected packages

• RubyGems view_component: >= 4.0.0, < 4.12.0 → fixed in 4.12.0

Description

Summary `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`. Affected Code Validated against: • Repository commit: `eea79445` • Ruby: `3.4.9` Relevant locations: • `lib/view_component/base.rb` • `render_in` • `around_render` • `__vc_maybe_escape_html` • `lib/view_component/template.rb` • `InlineCall#safe_method_name_call` • `lib/view_component/collection.rb` • `Collection#render_in` Key code paths: ```ruby lib/view_component/base.rb around_render do render_template_for(@__vc_requested_details).to_s end ``` ```ruby lib/view_component/template.rb proc do __vc_maybe_escape_html(send(m)) do Kernel.warn(...) end end ``` ```ruby lib/view_component/collection.rb components.map do |component| component.render_in(view_context, &block) end.join(rendered_spacer(view_context)).html_safe ``` Root Cause 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: raw Collection rendering then amplifies the issue by calling `.html_safe` on the joined result. Proof of Concept Run from the repository root: ```ruby $LOAD_PATH.unshift File.expand_path("lib", Dir.pwd) require "action_controller/railtie" require "rack/mock" require "view_component/base" class PocController " class UnsafeCallComponent around_render_raw=true html_safe=false collection= collection_raw=true html_safe=true controller_render_to_string= controller_raw=true html_safe=false ``` The control case confirms that normal `#call` output is escaped. The `around_render` cases confirm that the same payload is emitted raw. Exploit Scenario A downstream application defines a component that uses `around_render` for tracing, layout wrapping, feature-flag fallback, error fallback, or instrumentation. If the hook returns a string containing request data, model attributes, CMS content, markdown output, or other attacker-controlled values, the value can be rendered as raw HTML. Example vulnerable pattern: ```ruby class BannerComponent #{@message}" end end ``` If `message` is user-controlled, scriptable HTML reaches the browser. Impact Successful exploitation allows XSS in applications using affected components. Depending on application context, impact can include: • session or token theft where cookies/tokens are accessible • authenticated actions as the victim • CSRF bypass through same-origin script execution • exfiltration of page data • credential phishing or UI redress inside trusted application origin The collection path is particularly risky because it converts the joined raw output to `html_safe`, which can suppress later escaping. Preconditions • The application defines or uses a component overriding `around_render`. • `around_render` returns or wraps attacker-influenced HTML-unsafe content. • The component is rendered in a browser-visible response. • Higher impact when rendered through `ViewComponent::Collection` or controller/direct rendering. Chaining Potential This finding can chain with: • preview routes or examples that accept URL parameters and render components • unsafe markdown or CMS content rendered inside `around_render` • CSP-disabled preview routes • applications that expose admin-only pages containing affected components Remediation Apply the same HTML-safety enforcement to `around_render` return values that is applied to normal inline `#call` output. Possible approaches: 1. Wrap the result of `around_render` with `__vc_maybe_escape_html` when the current template is HTML. 2. Require `around_render` to return an `ActiveSupport::SafeBuffer` to opt into raw HTML. 3. In collection rendering, avoid blindly calling `.html_safe` on joined component outputs unless each item has been normalized through the same safety boundary.

Related

Alias · CVE (1)

  • CVE-2026-54498 view_component is a framework for building reusable, testable, and encapsulated view components in Ruby on Rails. vulnerability

Weakness · CWE (1)

  • CWE-79 Improper Neutralization of Input During Web Page Generation weakness

References