GitHub Advisoryadvisory · RubyGems
GHSA-97jw-64cj-jc58 ViewComponent: around_render HTML-Safety Bypass
HIGH
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
- https://github.com/ViewComponent/view_component/security/advisories/GHSA-97jw-64cj-jc58 web
- https://github.com/ViewComponent/view_component/commit/48e5fd2d602344c7d33019fbc5c8b087e315bb78 web
- https://github.com/ViewComponent/view_component package
- https://github.com/ViewComponent/view_component/releases/tag/v4.12.0 web
- https://github.com/rubysec/ruby-advisory-db/blob/master/gems/view_component/CVE-2026-54498.yml web
- https://www.cve.org/CVERecord/SearchResults?query=CVE-2026-54498 web