CVE-2026-54497
Ruby vulnerability analysis and mitigation

Overview

CVE-2026-54497 is a stale render context vulnerability in the view_component Ruby gem (ViewComponent) titled "Reused Component Instances Retain Stale Render Context." ViewComponent::Base instances memoize render-scoped objects (helpers, controller, request, view_flow, format/variant details, and slot child context) on first render via ||=, and fail to reset them on subsequent renders. If the same component, collection, or spacer instance is reused across requests, users, tenants, or threads, later renders inherit stale context from earlier ones. Affected versions are >= 4.0.0, < 4.12.0 of the view_component RubyGem; versions below 4.0.0 are unaffected. The vulnerability was first published on June 4, 2026, and carries a CVSS v3.1 base score of 6.8 (Medium), with an alternative High score of 8.2 if cross-user scope change is accepted (GitHub Advisory, ViewComponent Advisory).

Technical details

The root cause is improper memoization of request-scoped state in ViewComponent::Base#render_in (CWE-362, CWE-488, CWE-668). Key instance variables — @__vc_original_view_context, @lookup_context, @view_flow, @__vc_requested_details, @__vc_controller, @__vc_helpers, and @__vc_request — are assigned using ||=, meaning they are only set on the first render and retained for all subsequent renders of the same instance. Additionally, ViewComponent::Collection memoizes child component instances (return @components if defined? @components), and slot children inherit the parent's original view context. The precondition for exploitation is that the same component, collection, slot, or spacer instance is rendered under more than one view context — a pattern that arises when applications store component instances in constants, singletons, memoized helpers, or shared registries. Normal per-request usage (render(MyComponent.new(...))) is not affected. A detailed proof-of-concept demonstrating stale authorization gates, stale Host headers, slot context leakage, and cross-thread context mixing is included in the advisory (ViewComponent Advisory, GitHub Advisory).

Impact

Successful exploitation can cause authorization-aware components to render privileged UI (e.g., admin action links) for lower-privileged or unauthenticated users, effectively bypassing UI-level authorization gates. Stale request.host data can result in absolute URLs or signed action links being generated with an attacker-controlled or admin Host header, enabling Host header poisoning and potential phishing or SSRF chaining. In multi-tenant applications, slot child context, content_for writes, format/variant selection, and user identity exposed through helpers can all leak across users or tenants. Under concurrent Rails servers such as Puma, cross-thread context corruption can cause one thread's render to use another thread's controller and request state entirely (ViewComponent Advisory).

Exploitation steps

  1. Identify a vulnerable application: Locate a Rails application using view_component gem versions >= 4.0.0, < 4.12.0 that stores component instances in a shared location (e.g., a singleton registry, memoized module-level variable, or constant).
  2. Prime the component with a privileged context: As or by triggering an admin user request, cause the shared component instance to be rendered for the first time. This sets the stale @__vc_controller, @__vc_helpers, @__vc_request, and related ivars to the admin's context via ||=.
  3. Trigger a guest render of the same instance: As a lower-privileged (guest) user, trigger a request that renders the same cached/shared component instance. Because render_in does not reset the memoized ivars, the guest's render uses the admin's helpers, controller, and request.
  4. Observe privileged UI leakage: The guest receives rendered output that includes admin-only UI elements (e.g., an impersonation link), stale admin Host header in generated absolute URLs, and stale user identity from helpers.current_user.
  5. Exploit concurrent rendering (optional): In a multi-threaded server (e.g., Puma), render the same component instance from two threads simultaneously. Due to the race condition, both threads may end up using the same (first-writer's) view context, leaking one user's data to another.

(ViewComponent Advisory, GitHub Advisory)

Indicators of compromise

  • Logs: Rails application logs showing a guest or low-privileged user receiving responses containing admin-only UI elements (e.g., admin action links, impersonation URLs) that should be suppressed by render? authorization gates.
  • Logs: Absolute URLs in rendered HTML containing a Host header belonging to a different user's request (e.g., http://admin.example/... appearing in a guest user's response).
  • Application Behavior: Reports from users seeing another user's name, role-specific content, or privileged action links in their dashboard or navigation components.
  • Application Behavior: ViewComponent::ReusedInstanceError exceptions in application logs (after upgrading to v4.12.0 with raise_on_reused_instances: true), indicating component instances are being shared across renders in application code.
  • Application Behavior: Warning messages in logs matching "ViewComponent instance of ... was rendered more than once" (when raise_on_reused_instances is set to false).

(ViewComponent Advisory)

Mitigation and workarounds

Upgrade the view_component gem to version 4.12.0 or later, which resets render-scoped instance variables (@__vc_controller, @__vc_helpers, @__vc_request, @__vc_original_view_context, @lookup_context, @view_flow, @__vc_requested_details) at the start of every render_in call and raises ViewComponent::ReusedInstanceError if the same instance is rendered more than once (v4.12.0 Release). If an immediate upgrade is not possible, audit application code for any pattern that stores a ViewComponent::Base instance in a constant, singleton, memoized module variable, or shared registry and replace it with per-render instantiation (render MyComponent.new(...)). As a temporary migration aid, set config.view_component.raise_on_reused_instances = false to emit a deprecation warning instead of raising, while still refreshing state — but this should not be used as a permanent workaround (GitHub Advisory, ViewComponent Advisory).

Community reactions

The advisory was published by ViewComponent maintainer joelhawksley on June 4, 2026, and was reviewed and added to the GitHub Advisory Database on July 15, 2026. The fix was shipped in the same release (v4.12.0) that addressed a separate HTML-safety bypass in around_render (GHSA-97jw-64cj-jc58), suggesting a coordinated security release. No significant external media coverage or notable researcher commentary beyond the official advisory has been identified at this time (v4.12.0 Release, GitHub Advisory).

Additional resources


SourceThis report was generated using AI

Related Ruby vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

GHSA-2x63-gw47-w4mmHIGH8.9
  • Ruby logoRuby
  • websocket-driver
NoYesJul 21, 2026
CVE-2026-61666HIGH8.9
  • Ruby logoRuby
  • websocket-driver
NoYesJul 21, 2026
GHSA-cj75-f6xr-r4g7MEDIUM5.1
  • Ruby logoRuby
  • rails-html-sanitizer
NoYesJul 21, 2026
GHSA-9wjq-cp2p-hrgfMEDIUM4.7
  • Ruby logoRuby
  • loofah
NoYesJul 21, 2026
GHSA-5qhf-9phg-95m2LOW2.3
  • Ruby logoRuby
  • loofah
NoYesJul 21, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management