Skip to main content

ViewComponent CVE-2026-44836

| EUVDEUVD-2026-31972 MEDIUM
Insecure Inherited Permissions (CWE-277)
2026-05-08 https://github.com/ViewComponent/view_component GHSA-7f3r-gwc9-2995
6.5
CVSS 3.1 · Vendor: https://github.com/ViewComponent/view_component
View

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain

  1. Recon
    Authenticated request to preview route
  2. Delivery
    URL path extracted as method name
  3. Exploit
    public_send dispatches render_with_template (inherited, not validated)
  4. Install
    template and locals parameters from request captured
  5. C2
    Rails render executes with attacker-supplied template path and locals
  6. Execute
    internal template rendered with access to secrets and config
  7. Impact
    response 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.

This Month Plan within 30 days. Why: MEDIUM severity (CVSS 4.0-6.9).
Patch available 0.0% exploitation probability (EPSS)

Get an e-mail when this CVE is exploited, patched or re-scored. Free account.

Alert me

AnalysisAIv1 – 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

view_component 3.0.0, < 4.9.0

Affected Packages

rubygems view_component fix: 4.9.0

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

Vendor (https://github.com/ViewComponent/view_component) PRIMARY 6.5 MEDIUM
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

Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
None
Availability
None

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.rb
  • app/controllers/concerns/view_component/preview_actions.rb
  • app/views/view_components/preview.html.erb

Relevant Code

app/controllers/concerns/view_component/preview_actions.rb:

ruby
@example_name = File.basename(params[:path])
@render_args = @preview.render_args(@example_name, params: params.permit!)

lib/view_component/preview.rb:

ruby
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:

erb
<%= render template: @render_args[:template], locals: @render_args[:locals] || {} %>

The UI only lists direct preview methods via:

ruby
public_instance_methods(false).map(&:to_s).sort

But render_args does not enforce that list before dispatching.

Exploit Flow

Example request:

text
GET /rails/view_components/my_component/render_with_template?template=internal/secret&locals[poc_local]=attacker-controlled-local&request_marker=attacker-controlled-request

Flow:

  1. my_component resolves to a valid preview.
  2. File.basename(params[:path]) returns render_with_template.
  3. render_args calls inherited ViewComponent::Preview#render_with_template.
  4. Request params provide template: "internal/secret" and locals: {...}.
  5. The preview view renders internal/secret with 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.rb
  • test/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:

bash
bundle exec ruby -Itest test/sandbox/test/security_preview_template_poc_test.rb

Equivalent standalone test:

ruby
# 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
end

Fixture template:

erb
<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:

ruby
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)
end

Add 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

EPSS Score
0.0%
Top 98% exploitable
Threat Intel
1
1 source
Data Quality
6 sources
Confidence: High

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.

SignalValue
Severity MEDIUM
CISA KEV No
Public POC No
EPSS 0.0%
Patch available Yes
Active threat No
Deciding rule
MEDIUM severity (CVSS 4.0-6.9)
What every action level means
Emergency Immediate action required. Criteria: CRITICAL + in CISA KEV (actively exploited) without patch, OR CRITICAL + EPSS > 30% without patch, OR CRITICAL + active threat signals without patch.
Act Now Prioritize within 24-48h. Criteria: in KEV with patch available, OR CRITICAL + public POC, OR HIGH + EPSS > 10%, OR CRITICAL + active threat, OR any CRITICAL severity.
This Week Schedule remediation this week. Criteria: HIGH severity (CVSS 7.0-8.9). Patch within normal change window.
This Month Plan within 30 days. Criteria: MEDIUM severity (CVSS 4.0-6.9), lower exploitation probability. Include in regular patch cycle.
Monitor Track and reassess. Criteria: LOW severity (CVSS 0.1-3.9), minimal exploitation risk. No immediate action needed.

SSVC AssessmentENISA

SSVC Decision· derived
Scheduled
Exploitation· derived
None
System Exposure· derived
Open
Automatable· derived
No
Human Impact· derived
Medium

Priority Score

32
Low Medium High Critical
KEV: 0
EPSS: 0
CVSS: +32
PoC: 0
Weaponized: 0
Threat intel: 0
Gov advisory: 0

Attack Technique

Information disclosure occurs when an application unintentionally exposes sensitive data that aids attackers in reconnaissance or directly compromises security.

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy