CVE-2026-54497
view_component: Reused Component Instances Retain Stale Render Context
view_component is a framework for building reusable, testable, and encapsulated view components in Ruby on Rails. From 4.0.0 until 4.12.0, ViewComponent::Base instances retain render-scoped objects across calls to render_in; if the same component, collection, or spacer component instance is reused across requests, users, tenants, or threads, later renders can use stale helpers, controller, request, view_flow, format/variant details, and slot child context from an earlier render. This can cause authorization-aware components to render privileged UI for a lower-privileged user, generate links using a stale Host header, leak slot/helper state, and mix request context under concurrent rendering. This issue is fixed in version 4.12.0.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- High
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
6.8
view_component: Reused Component Instances Retain Stale Render Context
view_component is a framework for building reusable, testable, and encapsulated view components in Ruby on Rails. From 4.0.0 until 4.12.0, ViewComponent::Base instances retain render-scoped objects across calls to render_in; if the same component, collection, or spacer component instance is reused across requests, users, tenants, or threads, later renders can use stale helpers, controller, request, view_flow, format/variant details, and slot child context from an earlier render. This can cause authorization-aware components to render privileged UI for a lower-privileged user, generate links using a stale Host header, leak slot/helper state, and mix request context under concurrent rendering. This issue is fixed in version 4.12.0.
- Record
CVE-2026-54497- CVSS 3.1
- 6.8 Medium
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N - Weakness
- CWE-362, CWE-488, CWE-668
- Updated
- 2026-11-02
EUVDEUVD-2026-45332
6.8
view_component is a framework for building reusable, testable, and encapsulated view components in Ruby on Rails. From 4.0.0 until 4.12.0, ViewComponent::Base instances retain render-scoped objects across calls to render_in; if the same component, collection, or spacer component instance is reused across requests, users, tenants, or threads, later renders can use stale helpers, controller, request, view_flow, format/variant details, and slot child context from an earlier render. This can cause authorization-aware components to render privileged UI for a lower-privileged user, generate links using a stale Host header, leak slot/helper state, and mix request context under concurrent rendering. This issue is fixed in version 4.12.0.
- Record
EUVD-2026-45332- CVSS 3.1
- 6.8 Medium
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-9h85-g7w3-rh49
6.8
ViewComponent: Reused Component Instances Retain Stale Render Context
Reused Component Instances Retain Stale Render Context
Summary
ViewComponent::Base instances retain multiple render-scoped objects across calls to render_in. If the same component, collection, or spacer component instance is reused across requests, users, tenants, or threads, later renders can use stale helpers, controller, request, view_flow, format/variant details, and slot child context from an earlier render.
This can cause authorization-aware components to render privileged UI for a lower-privileged user, generate links using a stale Host header, leak slot/helper state, and mix request context under concurrent rendering.
Severity
The PoC demonstrates cross-user authorization impact in a realistic downstream application pattern. If the receiving program accepts downstream cross-user authorization impact as a scope-changing impact for a framework vulnerability, an alternative High score can be assigned:
Alternative CVSS: 8.2
Alternative vector: CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N
Affected Code
Validated against:
- Repository commit:
eea79445 - Ruby:
3.4.9
Relevant locations:
lib/view_component/base.rbrender_incontrollerhelpers__vc_request
lib/view_component/slot.rbSlot#to_s
lib/view_component/slotable.rb- slot storage in
@__vc_set_slots
- slot storage in
lib/view_component/collection.rb- child component memoization and spacer rendering
Key retained state:
@view_context = view_context
self.__vc_original_view_context ||= view_context
@lookup_context ||= view_context.lookup_context
@view_flow ||= view_context.view_flow
@__vc_requested_details ||= @lookup_context.vc_requested_details
@__vc_controller ||= view_context.controller
@__vc_helpers ||= __vc_original_view_context || controller.view_context
@__vc_request ||= controller.request if controller.respond_to?(:request)
Slot children also inherit the parent original view context:
@__vc_component_instance.__vc_original_view_context = @parent.__vc_original_view_context
Collections memoize child component instances:
return @components if defined? @components
Root Cause
Component instances are mutable render objects. render_in updates some per-render fields, but many request-scoped values are memoized using ||= or stored for later slot/collection rendering.
There is no runtime guard preventing a component instance from being rendered multiple times under different view contexts, and there is no full reset of render-scoped state at the start of each render.
Maintainer discussion in prior PRs notes that component instances should not be shared between renders, but the current runtime does not enforce this invariant.
Proof of Concept
The following PoC demonstrates four independent effects:
- stale authorization gate
- stale Host/request data in generated absolute URLs
- stale slot child context
- cross-thread context mixing
Run from the repository root:
$LOAD_PATH.unshift File.expand_path("lib", Dir.pwd)
require "action_controller/railtie"
require "rack/mock"
require "view_component/base"
class ReusePocController < ActionController::Base
helper_method :current_user, :admin?
attr_accessor :current_user, :role
def admin? = role == :admin
end
routes = ActionDispatch::Routing::RouteSet.new
routes.draw { get "/accounts/:id", to: "accounts#show" }
ReusePocController.include routes.url_helpers
class AdminPanelComponent < ViewComponent::Base
def render? = helpers.admin?
def call
href = helpers.url_for(controller: "accounts", action: "show", id: 42, only_path: false)
"ADMIN user=#{helpers.current_user};host=#{request.host};href=#{href}".html_safe
end
end
class UrlOnlyComponent < ViewComponent::Base
def call
href = helpers.url_for(controller: "accounts", action: "show", id: 42, only_path: false)
"user=#{helpers.current_user};host=#{request.host};href=#{href}".html_safe
end
end
class…
- Record
GHSA-9h85-g7w3-rh49- CVSS 3.1
- 6.8 Medium
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N - Weakness
- CWE-362, CWE-488, CWE-668
- Updated
- 2026-11-02
NVD
6.8
view_component is a framework for building reusable, testable, and encapsulated view components in Ruby on Rails. From 4.0.0 until 4.12.0, ViewComponent::Base instances retain render-scoped objects across calls to render_in; if the same component, collection, or spacer component instance is reused across requests, users, tenants, or threads, later renders can use stale helpers, controller, request, view_flow, format/variant details, and slot child context from an earlier render. This can cause authorization-aware components to render privileged UI for a lower-privileged user, generate links using a stale Host header, leak slot/helper state, and mix request context under concurrent rendering. This issue is fixed in version 4.12.0.
- Record
CVE-2026-54497- CVSS 3.1
- 6.8 Medium
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N - Weakness
- CWE-362, CWE-488, CWE-668
- Updated
- 2026-11-02
OSV
6.8
view_component: Reused Component Instances Retain Stale Render Context
view_component is a framework for building reusable, testable, and encapsulated view components in Ruby on Rails. From 4.0.0 until 4.12.0, ViewComponent::Base instances retain render-scoped objects across calls to render_in; if the same component, collection, or spacer component instance is reused across requests, users, tenants, or threads, later renders can use stale helpers, controller, request, view_flow, format/variant details, and slot child context from an earlier render. This can cause authorization-aware components to render privileged UI for a lower-privileged user, generate links using a stale Host header, leak slot/helper state, and mix request context under concurrent rendering. This issue is fixed in version 4.12.0.
- Record
CVE-2026-54497- CVSS 3.1
- 6.8 Medium
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N - Weakness
- CWE-362, CWE-488, CWE-668
- Updated
- 2026-11-02
OSVGHSA-9h85-g7w3-rh49
6.8
ViewComponent: Reused Component Instances Retain Stale Render Context
Reused Component Instances Retain Stale Render Context
Summary
ViewComponent::Base instances retain multiple render-scoped objects across calls to render_in. If the same component, collection, or spacer component instance is reused across requests, users, tenants, or threads, later renders can use stale helpers, controller, request, view_flow, format/variant details, and slot child context from an earlier render.
This can cause authorization-aware components to render privileged UI for a lower-privileged user, generate links using a stale Host header, leak slot/helper state, and mix request context under concurrent rendering.
Severity
The PoC demonstrates cross-user authorization impact in a realistic downstream application pattern. If the receiving program accepts downstream cross-user authorization impact as a scope-changing impact for a framework vulnerability, an alternative High score can be assigned:
Alternative CVSS: 8.2
Alternative vector: CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N
Affected Code
Validated against:
- Repository commit:
eea79445 - Ruby:
3.4.9
Relevant locations:
lib/view_component/base.rbrender_incontrollerhelpers__vc_request
lib/view_component/slot.rbSlot#to_s
lib/view_component/slotable.rb- slot storage in
@__vc_set_slots
- slot storage in
lib/view_component/collection.rb- child component memoization and spacer rendering
Key retained state:
@view_context = view_context
self.__vc_original_view_context ||= view_context
@lookup_context ||= view_context.lookup_context
@view_flow ||= view_context.view_flow
@__vc_requested_details ||= @lookup_context.vc_requested_details
@__vc_controller ||= view_context.controller
@__vc_helpers ||= __vc_original_view_context || controller.view_context
@__vc_request ||= controller.request if controller.respond_to?(:request)
Slot children also inherit the parent original view context:
@__vc_component_instance.__vc_original_view_context = @parent.__vc_original_view_context
Collections memoize child component instances:
return @components if defined? @components
Root Cause
Component instances are mutable render objects. render_in updates some per-render fields, but many request-scoped values are memoized using ||= or stored for later slot/collection rendering.
There is no runtime guard preventing a component instance from being rendered multiple times under different view contexts, and there is no full reset of render-scoped state at the start of each render.
Maintainer discussion in prior PRs notes that component instances should not be shared between renders, but the current runtime does not enforce this invariant.
Proof of Concept
The following PoC demonstrates four independent effects:
- stale authorization gate
- stale Host/request data in generated absolute URLs
- stale slot child context
- cross-thread context mixing
Run from the repository root:
$LOAD_PATH.unshift File.expand_path("lib", Dir.pwd)
require "action_controller/railtie"
require "rack/mock"
require "view_component/base"
class ReusePocController < ActionController::Base
helper_method :current_user, :admin?
attr_accessor :current_user, :role
def admin? = role == :admin
end
routes = ActionDispatch::Routing::RouteSet.new
routes.draw { get "/accounts/:id", to: "accounts#show" }
ReusePocController.include routes.url_helpers
class AdminPanelComponent < ViewComponent::Base
def render? = helpers.admin?
def call
href = helpers.url_for(controller: "accounts", action: "show", id: 42, only_path: false)
"ADMIN user=#{helpers.current_user};host=#{request.host};href=#{href}".html_safe
end
end
class UrlOnlyComponent < ViewComponent::Base
def call
href = helpers.url_for(controller: "accounts", action: "show", id: 42, only_path: false)
"user=#{helpers.current_user};host=#{request.host};href=#{href}".html_safe
end
end
class…
- Record
GHSA-9h85-g7w3-rh49- CVSS 3.1
- 6.8 Medium
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N - Weakness
- CWE-362, CWE-488, CWE-668
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
view_componentRubyGems |
4.0.0 up to 4.12.0 | 4.12.0 |
view_componentRubyGems |
4.0.0 up to 4.12.0, plus listed versions 4.0.14.0.24.1.04.1.14.10.0 Show 9 moreShow less4.11.04.2.04.3.04.4.04.5.04.6.04.7.04.8.04.9.0 |
4.12.0 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-54497 is a medium vulnerability (CVSS 6.8) in Github View Component, published July 15, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.33%, the 26th percentile. Fixed in view_component 4.12.0.
References
github.com/ViewComponent/view_component/security/advisories/GHSA-9h85-g7w3-rh49
github.com/ViewComponent/view_component/commit/6796b2e89d0bd7b9d7d763a86275e5334731dd61
github.com/ViewComponent/view_component/releases/tag/v4.12.0
github.com/ViewComponent/view_component/commit/7b05073be28037f7d5ff141e9dd42f3cf47956a4
github.com/rubysec/ruby-advisory-db/blob/master/gems/view_component/CVE-2026-54497.yml
cve.org/CVERecord/SearchResults?query=CVE-2026-54497
Left out here: the rest of 2 source descriptions. The JSON record has them.