CVE-2026-125110: CVE-2026-125110: Path Canonicalization Mismatch and Security Header Bypass in Rack::Static
CVE-2026-125110: Path Canonicalization Mismatch and Security Header Bypass in Rack::Static Vulnerability ID: CVE-2026-125110 CVSS Score: 5.3 Published: 2026-11-10 CVE-2026-125110 is a path canonicalization mismatch
CVE-2026-125110: Path Canonicalization Mismatch and Security Header Bypass in Rack::Static
Vulnerability ID: CVE-2026-125110
CVSS Score: 5.3
Published: 2026-11-10
CVE-2026-125110 is a path canonicalization mismatch vulnerability in Rack (specifically within the Rack::Static middleware component). When serving static files, Rack normalizes the requested URL path to resolve the physical file on disk, but evaluates configured path-specific header rules against an unnormalized, raw path that has only undergone URL percent-decoding. Unauthenticated remote attackers can exploit this discrepancy by injecting raw or percent-encoded dot-segments into HTTP requests, causing Rack to serve restricted static assets without their intended security headers.
TL;DR
An order-of-operations flaw in Rack::Static (CWE-180) causes path-specific header rules to be evaluated before dot-segment path normalization. Attackers can use traversal sequences like /css/../admin/secret.html to retrieve static files stripped of protective HTTP headers such as Content-Security-Policy, X-Frame-Options, and restrictive Cache-Control directives.
⚠️ Exploit Status: POC
Technical Details
- CVE / Advisory ID: CVE-2026-125110 / GHSA-wvg4-6p58-3gh3
- Weakness Class: CWE-180 (Incorrect Behavior Order: Validate Before Canonicalize)
- Affected Component: Rack::Static#applicable_rules (lib/rack/static.rb)
- Attack Vector: Network (Unauthenticated HTTP GET with raw or encoded dot-segments)
- CVSS v3.1 Score: 5.3 Medium (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N)
- EPSS Score: 0.25% (16.56th Percentile)
- Security Impact: Bypass of path-specific HTTP security and caching headers (CSP, X-Frame-Options, Cache-Control)
- Patched Versions: Rack 2.2.25, 3.1.23, 3.2.8
Affected Systems
- Ruby Rack (rack RubyGem)
- Ruby on Rails / Sinatra / Rack-based web applications utilizing Rack::Static with path-specific header_rules
-
rack: < 2.2.25 (Fixed in:
2.2.25) -
rack: >= 3.0, < 3.1.23 (Fixed in:
3.1.23) -
rack: >= 3.2, < 3.2.8 (Fixed in:
3.2.8)
Code Analysis
Commit: 18a07fe
Normalize path using Rack::Utils.clean_path_info in Rack::Static#applicable_rules before matching header rules
File: lib/rack/static.rb
@@ -168,7 +168,7 @@ def call(env)
# Convert HTTP header rules to HTTP headers
def applicable_rules(path)
- path = ::Rack::Utils.unescape_path(path)
+ path = ::Rack::Utils.clean_path_info(::Rack::Utils.unescape_path(path))
@header_rules.find_all do |rule, new_headers|
case rule
Commit: 9d7f194
Backport fix for Rack::Static#applicable_rules path normalization mismatch
File: lib/rack/static.rb
@@ -168,7 +168,7 @@ def call(env)
# Convert HTTP header rules to HTTP headers
def applicable_rules(path)
- path = ::Rack::Utils.unescape_path(path)
+ path = ::Rack::Utils.clean_path_info(::Rack::Utils.unescape_path(path))
@header_rules.find_all do |rule, new_headers|
case rule
Commit: e88097c
Backport fix for Rack::Static#applicable_rules path normalization mismatch (2.2 branch)
File: lib/rack/static.rb
@@ -168,7 +168,7 @@ def call(env)
# Convert HTTP header rules to HTTP headers
def applicable_rules(path)
- path = ::Rack::Utils.unescape_path(path)
+ path = ::Rack::Utils.clean_path_info(::Rack::Utils.unescape_path(path))
@header_rules.find_all do |rule, new_headers|
case rule
Exploit Details
- GitHub: Official upstream regression test suite in test/spec_static.rb demonstrating four dot-segment and percent-encoded bypass payloads.
Mitigation Strategies
- Upgrade the Rack gem to a patched release (2.2.25, 3.1.23, or 3.2.8) to ensure path canonicalization occurs before header rule matching.
- Offload static asset serving and security header enforcement to an upstream reverse proxy (such as NGINX or Envoy) or CDN that normalizes URI paths prior to rule evaluation.
- Invert Rack::Static header rule logic so that restrictive security and caching headers are applied globally via the :all rule, rather than relying on path-specific overrides.
- Move sensitive static documents and user-uploaded files out of Rack::Static directories and serve them via authenticated controller endpoints.
Remediation Steps:
- Audit the application's Gemfile.lock to determine if an affected version of rack (< 2.2.25, >= 3.0 < 3.1.23, or >= 3.2 < 3.2.8) is installed.
- Inspect config.ru and environment configuration files for uses of Rack::Static containing path-specific :header_rules options.
- Run
bundle update rackto upgrade to version 2.2.25, 3.1.23, or 3.2.8 (or higher) depending on your active release branch. - Verify that automated test suites pass and redeploy the updated application containers or server processes.
- Purge upstream CDN or reverse proxy caches if sensitive static files may have been publicly cached due to previous Cache-Control rule bypasses.
References
- GitHub Security Advisory GHSA-wvg4-6p58-3gh3
- Rack Patch Commit (18a07fe553afb4d8a678d6a948cd6ba1e11e28be)
- Rack Patch Commit (9d7f19484ffd5ed5e032678c26ee6eff96d3a0a3)
- Rack Patch Commit (e88097ccb88be44d06d47b42daffe04929516ee4)
- NVD - CVE-2026-125110
- CVE.org Record - CVE-2026-125110
- CVEListV5 JSON Record - CVE-2026-125110
Read the full report for CVE-2026-125110 on our website for more details including interactive diagrams and full exploit analysis.
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.