Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-54498

CVE-2026-54498: ViewComponent XSS Vulnerability

CVE-2026-54498 is an XSS vulnerability in ViewComponent for Ruby on Rails affecting versions 4.0.0 to 4.11.x. This flaw allows HTML-unsafe strings to bypass escaping, creating cross-site scripting risks. Learn the technical details, affected versions, impact, and mitigation steps.

Published:

CVE-2026-54498 Overview

CVE-2026-54498 is a cross-site scripting (XSS) vulnerability in view_component, a framework for building reusable, testable, and encapsulated view components in Ruby on Rails. The flaw affects versions 4.0.0 through versions prior to 4.12.0. The ViewComponent::Base#around_render method can return HTML-unsafe strings that bypass the escaping applied to normal #call return values. ViewComponent::Collection#render_in amplifies the issue by joining per-item results and marking the entire output html_safe, converting raw unsafe output into an ActiveSupport::SafeBuffer. The maintainers fixed the issue in version 4.12.0.

Critical Impact

Attackers can inject arbitrary HTML or JavaScript into rendered pages when applications use around_render to wrap content that includes user-controlled data, enabling session theft, credential capture, and account takeover.

Affected Products

  • ViewComponent gem versions 4.0.0 through 4.11.x
  • Ruby on Rails applications using ViewComponent::Base#around_render
  • Applications using ViewComponent::Collection#render_in with unsafe wrapping logic

Discovery Timeline

  • 2026-07-17 - CVE-2026-54498 published to NVD
  • 2026-07-23 - Last updated in NVD database

Technical Details for CVE-2026-54498

Vulnerability Analysis

The vulnerability stems from an output-safety gap in the ViewComponent rendering pipeline [CWE-79]. Normal #call return values pass through Rails' HTML escaping logic, which converts user-controlled data into safe HTML entities. The around_render hook, however, allowed applications to substitute the rendered string with an arbitrary return value that bypassed this escaping step.

Downstream applications commonly use around_render to wrap, replace, instrument, or conditionally return rendered content. When developers concatenated user-controlled data with the inner rendered template inside this hook, the resulting string was returned verbatim without HTML escaping. ViewComponent::Collection#render_in compounded the risk by calling .join(...).html_safe on the aggregated output, promoting attacker-controlled bytes to an ActiveSupport::SafeBuffer that Rails renders directly to the client.

Root Cause

The root cause is inconsistent HTML-safety enforcement between #call and around_render return paths in lib/view_component/base.rb. The framework treated the block return value as authoritative without verifying that the string returned from around_render retained the html_safe? marker. In lib/view_component/collection.rb, the use of String#join followed by html_safe discarded per-item safety information and blanket-marked the joined result as safe.

Attack Vector

Exploitation requires an application that uses around_render to compose output containing user-controlled data, such as request parameters, database fields sourced from other users, or headers. An attacker submits a payload containing HTML or JavaScript to a form field, URL parameter, or API endpoint whose value is later rendered inside a component wrapped by around_render. Because the escape step is skipped, the browser interprets the payload as active markup.

ruby
         value = nil
 
         @output_buffer.with_buffer do
-          rendered_template =
-            around_render do
-              render_template_for(@__vc_requested_details).to_s
-            end
+          inner_rendered_template = nil
+          around_rendered_template = around_render do
+            inner_rendered_template = render_template_for(@__vc_requested_details).to_s
+          end
+
+          # If `around_render` returned the same object the block yielded, the inner
+          # template's escaping is authoritative and we can trust the result. If the
+          # user replaced/wrapped the value, re-check HTML safety to prevent
+          # bypassing the escaping applied to normal `#call` return values
+          # (GHSA-97jw-64cj-jc58).
+          rendered_template = if around_rendered_template.equal?(inner_rendered_template)
+            around_rendered_template
+          else
+            __vc_safe_around_render_output(around_rendered_template)
+          end

Source: GitHub Commit 48e5fd2

The patch introduces __vc_safe_around_render_output to re-check HTML safety whenever the returned object differs from the yielded inner template. The collection fix replaces join(...).html_safe with safe_join, which escapes non-safe strings before concatenation:

ruby
     def render_in(view_context, **_, &block)
-      components.map do |component|
+      rendered = components.map do |component|
         component.render_in(view_context, &block)
-      end.join(rendered_spacer(view_context)).html_safe
+      end
+      safe_join(rendered, rendered_spacer(view_context))
     end

Source: GitHub Commit 48e5fd2

Detection Methods for CVE-2026-54498

Indicators of Compromise

  • Unexpected <script> tags, on*= event handlers, or javascript: URIs appearing in server-rendered HTML responses from ViewComponent-based routes
  • Application logs showing HTML metacharacters (<, >, ", ') in request parameters that reach controllers rendering components with around_render hooks
  • Outbound requests from client browsers to unfamiliar domains immediately after loading pages that render user-generated content through ViewComponent

Detection Strategies

  • Perform a code audit of every around_render implementation in the application and verify that any string interpolation uses html_safe-aware helpers or explicitly escapes user input
  • Scan the Gemfile.lock across all repositories for view_component versions between 4.0.0 and 4.11.x
  • Enable a Content Security Policy (CSP) in report-only mode to surface inline script executions that indicate injection attempts

Monitoring Recommendations

  • Monitor web application firewall (WAF) logs for XSS payload signatures targeting endpoints backed by ViewComponent renderers
  • Alert on CSP violation reports containing script-src or inline violations originating from authenticated user sessions
  • Track browser telemetry for unexpected DOM mutations or script execution on pages rendered by component collections

How to Mitigate CVE-2026-54498

Immediate Actions Required

  • Upgrade the view_component gem to version 4.12.0 or later in all Rails applications
  • Audit every custom around_render implementation and confirm that returned values are either html_safe by construction or explicitly escaped with ERB::Util.html_escape
  • Review any code that calls .html_safe on aggregated component output and replace it with safe_join

Patch Information

The fix is available in ViewComponent v4.12.0. The patch adds __vc_safe_around_render_output to re-validate HTML safety when around_render replaces the block's return value, and replaces the unsafe join(...).html_safe in ViewComponent::Collection#render_in with safe_join from ActionView::Helpers::OutputSafetyHelper. Full technical details are available in the GHSA-97jw-64cj-jc58 advisory.

Workarounds

  • Remove or refactor around_render hooks that interpolate user-controlled data until the upgrade is deployed
  • Wrap any user input inside around_render with ERB::Util.html_escape(value) before concatenation with the inner rendered template
  • Apply a strict Content-Security-Policy header that disallows inline scripts and untrusted sources to reduce the impact of successful injection
bash
# Update Gemfile constraint
bundle update view_component --conservative

# Verify installed version
bundle info view_component | grep -i version

# Confirm no vulnerable versions remain
grep -R "view_component" Gemfile.lock | grep -E "4\.(0|1|2|3|4|5|6|7|8|9|10|11)\."

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.