CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-125110

CVE-2026-125110: Path Canonicalization Mismatch and Security Header Bypass in Rack::Static

Amit Schendel
Amit Schendel
Senior Security Researcher

Nov 10, 2026·10 min read·5 visits

Executive Summary (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.

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.

Vulnerability Overview

Rack (rack) is the foundational modular web server interface for the Ruby ecosystem, providing a unified API connecting web servers and frameworks such as Ruby on Rails, Sinatra, and Hanami. Among its built-in middleware components is Rack::Static, which intercepts incoming HTTP requests for static assets (such as stylesheets, JavaScript files, images, and static HTML documents) and serves them directly from a configured root directory without invoking the downstream Ruby application.

In addition to basic file resolution, Rack::Static allows developers to define custom HTTP response headers through the :header_rules configuration option. This mechanism maps specific URL path prefixes, regular expressions, or file extensions to sets of HTTP headers. Security teams rely on :header_rules to enforce critical browser-side security policies—including Content-Security-Policy (CSP), X-Frame-Options, Content-Disposition, and Cache-Control—on sensitive directory trees or user-uploaded static assets.

CVE-2026-125110 (also tracked as GitHub Security Advisory GHSA-wvg4-6p58-3gh3) is a path canonicalization mismatch vulnerability classified under CWE-180 (Incorrect Behavior Order: Validate Before Canonicalize). When processing an incoming request, Rack::Static resolves the target file on the filesystem using a normalized path where dot-segments (.. and .) are collapsed. However, the middleware evaluates :header_rules against a path string that has only been percent-decoded, omitting the dot-segment normalization step.

Because of this discrepancy between the file retrieval path and the policy evaluation path, an unauthenticated remote attacker can construct requests containing dot-segments (for example, /public/../admin/restricted.html) that resolve to the target file while evading path-specific rule matchers. Consequently, the web server returns the requested static asset stripped of its protective HTTP response headers.

Root Cause Analysis

The root cause of CVE-2026-125110 lies in an inconsistent application of path canonicalization functions within lib/rack/static.rb. Rack provides two distinct utility methods in Rack::Utils for processing URL paths: Rack::Utils.unescape_path, which decodes percent-encoded octets (converting %2F to / and %2E to .), and Rack::Utils.clean_path_info, which canonicalizes path strings by resolving relative dot-segments (.. and .) and collapsing redundant directory separators.

When an HTTP request enters Rack::Static#call, the middleware checks whether the request targets a configured static route and then delegates physical file lookup and delivery to Rack::Files (formerly Rack::File). During this file resolution phase, the path is sanitized using both unescape_path and clean_path_info. This ensures that a request containing relative traversal sequences is safely collapsed to its canonical form within the designated static root before interacting with the underlying operating system filesystem.

Concurrently, Rack::Static invokes its internal helper method applicable_rules(path) to iterate through the @header_rules array and compile the HTTP headers to attach to the response. Prior to the patch, applicable_rules(path) executed ::Rack::Utils.unescape_path(path) on the incoming PATH_INFO string, but failed to wrap the result in ::Rack::Utils.clean_path_info.

This creates a classic time-of-check to time-of-use (TOCTOU) impedance mismatch between policy evaluation and resource access. When an attacker submits a path beginning with an benign prefix followed by a parent directory traversal—such as /css/../admin/secret.html or its percent-encoded equivalent /css/%2E%2E/admin/secret.html—applicable_rules evaluates the literal string /css/../admin/secret.html. Any rule checking if the path starts with /admin/ (via String prefix matching or anchored Regexp matching like /^\/admin\//) evaluates to false, while the file server collapses the path to /admin/secret.html and serves the restricted file.

Code Analysis

In lib/rack/static.rb, Rack::Static supports several rule formats within the :header_rules configuration array: :all (matches every file), :fonts (matches common web font extensions), String (matches if the request path starts with the given string prefix), Regexp (matches if the regular expression matches the request path), and Array (matches file extensions).

In affected versions of Rack (< 2.2.25, >= 3.0, < 3.1.23, and >= 3.2, < 3.2.8), the applicable_rules method was implemented as follows:

# File: lib/rack/static.rb (Vulnerable Implementation)
# Convert HTTP header rules to HTTP headers
def applicable_rules(path)
  # FLAW: Only decodes percent-encoding; does not collapse '..' or '.' segments
  path = ::Rack::Utils.unescape_path(path)
 
  @header_rules.find_all do |rule, new_headers|
    case rule
    when :all
      true
    when :fonts
      /\.(?:ttf|otf|eot|woff2|woff)\z/.match?(path)
    when String
      # Prefix check fails if 'path' starts with '/css/../' instead of '/admin/'
      path.start_with?(rule)
    when Regexp
      rule.match?(path)
    when Array
      /\.(?:#{rule.join('|')})\z/.match?(path)
    else
      false
    end
  end
end

Because String rules rely on path.start_with?(rule) and Regexp rules frequently anchor against the leading directory path, any unnormalized dot-segment prepended to the path shifts the starting characters of path. Meanwhile, extension-based rules (:fonts and Array) match against the end of the string (\z) and remain largely unaffected unless dot-segments are appended to the end of the URI in a manner that still resolves on disk.

The official patch, committed across all maintained release branches (18a07fe553afb4d8a678d6a948cd6ba1e11e28be, 9d7f19484ffd5ed5e032678c26ee6eff96d3a0a3, and e88097ccb88be44d06d47b42daffe04929516ee4), resolves the issue by passing the unescaped path directly into ::Rack::Utils.clean_path_info before iterating over @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

> [!NOTE] > Fix Completeness Assessment: The fix is complete and directly eliminates the canonicalization discrepancy within Rack::Static. By invoking ::Rack::Utils.clean_path_info(::Rack::Utils.unescape_path(path)), applicable_rules now executes the exact same transformation sequence in the exact same order as the underlying file server. Whether the attacker supplies raw dot-segments (..), percent-encoded dot-segments (%2e%2e), or percent-encoded slashes (%2f), unescape_path first converts all encoded characters into literal ASCII characters, and clean_path_info immediately collapses the resulting traversal sequences prior to rule evaluation.

Exploitation

Exploiting CVE-2026-125110 requires no authentication, special privileges, or complex timing. The sole prerequisite is that the target Ruby web application uses Rack::Static configured with path-specific :header_rules (specifically String prefix rules or path-sensitive Regexp rules) to apply security or caching headers to specific static directories.

Consider a Rack application configured with the following middleware options, as demonstrated in the upstream regression test suite (test/spec_static.rb):

opts = {
  urls: ["/css", "/admin"],
  root: dir,
  header_rules: [
    [:all, { 'cache-control' => 'public, max-age=100' }],
    ['/admin/', {
      'cache-control' => 'private, no-store',
      'x-frame-options' => 'DENY'
    }]
  ]
}

In this configuration, any file served under /admin/ is intended to override the global public, max-age=100 cache directive with private, no-store and append x-frame-options: DENY to prevent framing. Note that when urls: ["/css", "/admin"] is configured, Rack::Static#can_serve checks if the incoming path begins with any prefix in urls. By starting the request path with /css, the attacker satisfies the outer middleware routing check (can_serve), ensuring Rack::Static intercepts the request.

An attacker can bypass the /admin/ rule using four distinct payload variations tested in the official regression suite:

  1. Standard Unencoded Dot-Segments:

    GET /css/../admin/secret.html HTTP/1.1
    Host: target-rack-app.local

    Note: Because some HTTP clients, browsers, or upstream reverse proxies automatically collapse unencoded /../ sequences before transmitting the request over the wire, attackers operating through standard web browsers or behind normalizing proxies will typically use percent-encoded variants.

  2. Percent-Encoded Dot-Segments:

    GET /css/%2E%2E/admin/secret.html HTTP/1.1
    Host: target-rack-app.local
  3. Fully Percent-Encoded Path Segments:

    GET /css%2F..%2Fadmin%2Fsecret.html HTTP/1.1
    Host: target-rack-app.local
  4. Mixed Encoded Path Segments:

    GET /foo/..%2Fadmin/secret.html HTTP/1.1
    Host: target-rack-app.local

When the unpatched server processes any of these four requests, it returns HTTP status 200 OK with the body of /admin/secret.html. However, because only the :all rule matched during applicable_rules, the response headers contain cache-control: public, max-age=100 and completely omit x-frame-options: DENY.

Impact Assessment

CVE-2026-125110 is rated with a CVSS v3.1 base score of 5.3 (Medium) via the vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N. The vulnerability does not grant arbitrary directory traversal outside the configured Rack::Static root directory (Confidentiality Impact: None), as Rack::Files still restricts file reads to the designated static root. Instead, the impact is centered on the bypass of HTTP response header integrity controls (Integrity Impact: Low).

The concrete security consequences depend directly on which headers an application relies upon Rack::Static to enforce:

  • Web Cache Deception and Cache Poisoning: If an application serves sensitive static exports, reports, or administrative views using a global public caching rule (Cache-Control: public, max-age=...) while overriding specific directories with Cache-Control: private, no-store, an attacker can request the sensitive asset via a dot-segment URL. Intermediate CDNs, reverse proxies, or shared caches will observe the fallback public directive and cache the confidential document, making it accessible to unauthorized users.
  • Clickjacking (UI Redressing): Static HTML pages (such as embedded administrative tools or confirmation forms) protected against framing via path-specific X-Frame-Options: DENY or Content-Security-Policy: frame-ancestors 'none' rules can be loaded inside an attacker-controlled <iframe> by referencing the dot-segment URL.
  • Cross-Site Scripting (XSS) and Content Injection: Applications that host user-uploaded static files (such as HTML, SVG, or XML documents) within a dedicated directory often mitigate script execution by applying a restrictive Content-Security-Policy (e.g., sandbox or default-src 'none') or X-Content-Type-Options: nosniff to the upload path. Bypassing these rules allows an attacker to upload a malicious SVG or HTML file and direct a victim to the dot-segment URL, executing arbitrary JavaScript in the context of the application's origin.
  • Forced Download Bypass: If a path rule applies Content-Disposition: attachment to prevent the browser from rendering potentially dangerous file types inline, bypassing the rule causes the browser to render the content directly inside the viewport.

According to FIRST EPSS metrics, CVE-2026-125110 currently holds an EPSS score of 0.00251 (0.25% probability of exploitation within 30 days, placing it in the 16.56th percentile), and is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog.

Remediation and Mitigation

The primary remediation is to upgrade the rack gem to a patched release that normalizes paths within Rack::Static#applicable_rules. The Rack maintenance team has released fixed versions across all supported branches:

  • Rack 2.2 Series: Upgrade to 2.2.25 or later.
  • Rack 3.0 / 3.1 Series: Upgrade to 3.1.23 or later.
  • Rack 3.2 Series: Upgrade to 3.2.8 or later.

Developers can update their application dependencies using Bundler:

bundle update rack

After updating, verify the installed version inside Gemfile.lock and restart all application server processes (such as Puma, Unicorn, or Passenger).

> [!NOTE] > If an immediate gem upgrade is not operationally feasible, security teams can implement compensating controls at the reverse proxy layer or within the application's middleware stack.

  1. Enforce Path Normalization and Header Policies at the Reverse Proxy: In production deployments, static asset delivery and security header assignment should ideally be offloaded to an upstream web server or reverse proxy (such as NGINX, Apache HTTP Server, or Envoy) or a Content Delivery Network (CDN). Ensure the upstream proxy is configured to normalize incoming request URIs and reject or collapse encoded dot-segments (%2e%2e) before evaluating location blocks or forwarding requests to the Rack backend.
  2. Use Global or Extension-Based Rules in Rack::Static: If Rack::Static must be used in an unpatched environment, avoid relying on path-prefix String or anchored Regexp rules to apply restrictive security headers. Instead, apply restrictive headers globally using :all (e.g., setting X-Frame-Options: DENY and Cache-Control: private, no-store as the default for :all), and only use path-specific rules to relax policies for explicitly safe public directories like /css/ or /assets/.
  3. Relocate Sensitive Assets Out of Public Static Roots: Confidential HTML files, administrative assets, or untrusted user uploads should not reside in directories served directly by Rack::Static. Move these files outside the public document root and serve them through authenticated application controllers where authorization and response headers are enforced programmatically.

Official Patches

RackOfficial GitHub Security Advisory for CVE-2026-125110 (GHSA-wvg4-6p58-3gh3)
RackUpstream patch commit 18a07fe553afb4d8a678d6a948cd6ba1e11e28be
RackUpstream patch commit 9d7f19484ffd5ed5e032678c26ee6eff96d3a0a3
RackUpstream patch commit e88097ccb88be44d06d47b42daffe04929516ee4

Fix Analysis (3)

Technical Appendix

CVSS Score
5.3/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
EPSS Probability
0.25%
Top 83% most exploited

Affected Systems

Ruby Rack (rack RubyGem)Ruby on Rails / Sinatra / Rack-based web applications utilizing Rack::Static with path-specific header_rules

Affected Versions Detail

Product
Affected Versions
Fixed Version
rack
Rack
< 2.2.252.2.25
rack
Rack
>= 3.0, < 3.1.233.1.23
rack
Rack
>= 3.2, < 3.2.83.2.8
AttributeDetail
CVE / Advisory IDCVE-2026-125110 / GHSA-wvg4-6p58-3gh3
Weakness ClassCWE-180 (Incorrect Behavior Order: Validate Before Canonicalize)
Affected ComponentRack::Static#applicable_rules (lib/rack/static.rb)
Attack VectorNetwork (Unauthenticated HTTP GET with raw or encoded dot-segments)
CVSS v3.1 Score5.3 Medium (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N)
EPSS Score0.25% (16.56th Percentile)
Security ImpactBypass of path-specific HTTP security and caching headers (CSP, X-Frame-Options, Cache-Control)
Patched VersionsRack 2.2.25, 3.1.23, 3.2.8

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1562.001Impair Defenses: Disable or Modify Tools
Defense Evasion
CWE-180
Incorrect Behavior Order: Validate Before Canonicalize

The product validates input before it is canonicalized, which prevents the product from detecting data that becomes invalid after the canonicalization step.

Known Exploits & Detection

GitHubOfficial upstream regression test suite in test/spec_static.rb demonstrating four dot-segment and percent-encoded bypass payloads.

Vulnerability Timeline

Fix commits authored and merged into Rack maintenance branches (18a07fe553afb4d8a678d6a948cd6ba1e11e28be, 9d7f19484ffd5ed5e032678c26ee6eff96d3a0a3, e88097ccb88be44d06d47b42daffe04929516ee4)
2026-10-30
GitHub Security Advisory GHSA-wvg4-6p58-3gh3 and CVE-2026-125110 officially published
2026-11-09
National Vulnerability Database (NVD) publishes record and assigns CVSS v3.1 score of 5.3
2026-11-09
FIRST EPSS assigns initial exploitation probability score (0.00251)
2026-11-10

References & Sources

  • [1]GitHub Security Advisory GHSA-wvg4-6p58-3gh3
  • [2]Rack Patch Commit (18a07fe553afb4d8a678d6a948cd6ba1e11e28be)
  • [3]Rack Patch Commit (9d7f19484ffd5ed5e032678c26ee6eff96d3a0a3)
  • [4]Rack Patch Commit (e88097ccb88be44d06d47b42daffe04929516ee4)
  • [5]NVD - CVE-2026-125110
  • [6]CVE.org Record - CVE-2026-125110
  • [7]CVEListV5 JSON Record - CVE-2026-125110

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•28 minutes ago•CVE-2026-125116
4.8

CVE-2026-125116: Type Confusion in Mongoose Discriminator Resolution

CVE-2026-125116 (GHSA-wr5m-5jph-8m96) is a type confusion vulnerability (CWE-843) in Mongoose, the MongoDB object modeling library for Node.js. When resolving discriminator models or schemas via user-supplied discriminator keys (defaulting to `__t`), Mongoose performs direct property indexing on plain JavaScript registry objects without verifying own-property ownership. Supplying inherited `Object.prototype` property names such as `'constructor'` causes Mongoose to resolve built-in functions rather than valid Mongoose constructors, resulting in unhandled runtime exceptions, schema validation bypasses, and persistent collection query denial of service.

Alon Barad
Alon Barad
2 views•11 min read
•about 1 hour ago•CVE-2026-125119
7.5

CVE-2026-125119: Connection-Level Filter Sanitization Bypass in Mongoose ODM

A flaw in Mongoose's query condition casting pipeline causes the `sanitizeFilter` configuration option to be silently ignored when defined at the connection level via `mongoose.connect()` or `mongoose.createConnection()`. Because internal query methods inspect `Connection.options` rather than `Connection.config`, applications relying on connection-scoped filter sanitization remain vulnerable to NoSQL query selector injection (CWE-943), permitting authentication bypass and unauthorized data access across Mongoose versions 6.x through 9.x.

Amit Schendel
Amit Schendel
3 views•9 min read
•about 3 hours ago•CVE-2026-118776
3.7

CVE-2026-118776: Improper PKCS#7 Padding Validation in node-forge CBC and ECB Cipher Modes

CVE-2026-118776 (also tracked as GHSA-2vgq-wchc-25w7) is an improper input and integrity check validation vulnerability affecting the node-forge cryptographic library prior to version 1.4.1. In vulnerable versions, the PKCS#7 unpadding implementations for Cipher Block Chaining (CBC) and Electronic Codebook (ECB) modes only examined the final byte of the decrypted buffer and permitted padding counts up to four times the cipher block size. This defect allowed malformed ciphertexts containing zero-length padding, oversized padding values, or mismatched preceding padding bytes to pass validation, resulting in silent plaintext truncation of up to four blocks and integrity verification bypass in applications relying on unpadding success.

Amit Schendel
Amit Schendel
2 views•10 min read
•about 4 hours ago•CVE-2026-118774
3.7

CVE-2026-118774: Improper Verification of Cryptographic Signature in node-forge X.509 Certificate Validation

CVE-2026-118774 (GHSA-9wg5-mj3p-v49q) is an improper cryptographic signature verification vulnerability (CWE-347) in node-forge versions prior to 1.4.1. When verifying an X.509 subordinate certificate via certificate.verify(child) or verifyCertificateChain(), the library erroneously selects the RSA padding scheme (e.g., PKCS#1 v1.5 vs. RSASSA-PSS) and RSASSA-PSS parameters from the issuer certificate rather than from the child certificate being verified. This enables an attacker to relabel a PKCS#1 v1.5-signed certificate as an RSASSA-PSS certificate without invalidating the signature check, bypassing downstream security policies that mandate RSASSA-PSS.

Amit Schendel
Amit Schendel
3 views•12 min read
•about 5 hours ago•CVE-2026-118670
8.8

CVE-2026-118670: DOM-Based Cross-Site Scripting in OHIF Viewers dicom-pdf Extension

CVE-2026-118670 (GHSA-xwgp-w3pj-q5h3) is a high-severity DOM-based Cross-Site Scripting (XSS) vulnerability in OHIF Viewers affecting the dicom-pdf extension module. When processing DICOM Encapsulated Document objects, the viewer extracts the untrusted MIMETypeOfEncapsulatedDocument attribute (tag 0042,0012) and uses it directly to instantiate an in-memory Blob. This Blob is then converted to a same-origin Object URL and embedded into the document via an HTML <object> element. Because browsers prioritize the resource's underlying MIME type over the <object> element's type attribute, an attacker who supplies a crafted DICOM file with a MIME type such as text/html can execute arbitrary JavaScript within the application's origin, compromising session tokens, local storage, and Patient Health Information (PHI).

Alon Barad
Alon Barad
3 views•9 min read
•about 6 hours ago•CVE-2026-103022
5.3

CVE-2026-103022: Denial of Service via Unhandled Unicode Exception and File Descriptor Leak in Urwid Web Display

A Denial of Service (DoS) vulnerability exists in the web display module (urwid/display/web.py) of the Urwid console user interface library for Python in versions prior to 4.0.7. The handle_short_request() function unconditionally encodes HTTP POST input as ASCII without exception handling and opens a FIFO pipe file descriptor without a guaranteed cleanup block. Submitting non-ASCII characters triggers an unhandled UnicodeEncodeError that terminates CGI request processing and leaks the open file descriptor. Additionally, the screen update polling routine decodes Unix domain socket streams iteratively as UTF-8 without exception handling or deterministic socket closure, enabling uncaught UnicodeDecodeError exceptions and socket leaks.

Alon Barad
Alon Barad
3 views•10 min read