CVE-2026-125110 is a medium-severity (CVSS 5.3) CWE-180 vulnerability in rack. A fix is available for rack — see the affected versions and patch details below.
Rack: Rack::Static header_rules bypass via dot-segment normalization mismatch
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
How urgent is this, really
Where this sits among everything scored
Real-World Exposure
rack💎rack💎rackReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects RubyGems packages — download data is not available via public APIs for these ecosystems.
Description
Summary
Rack::Static normalizes the request path with Utils.clean_path_info when deciding which file to serve, but matches header_rules against a path that is only URL-decoded. A request containing dot segments, raw or percent-encoded, is served the normalized target file while the header rules for that file's location are not applied.
This allows an attacker to receive a protected static file without the security headers configured for it.
Details
Rack::Static#call computes the served path as Utils.clean_path_info(Utils.unescape_path(path)). Rack::Static#applicable_rules applies only Utils.unescape_path before testing string and regular expression rules. A request for /assets/../uploads/file.html or /assets/..%2fuploads/file.html is served as uploads/file.html, but the decoded path /assets/../uploads/file.html does not start with uploads, so a rule scoped to that directory never matches.
The fix for CVE-2026-34786 (GHSA-q4qf-9j86-f5mh) added URL decoding to rule matching but did not add dot segment normalization, so versions that include that fix remain affected.
Impact
Applications that use Rack::Static header_rules to attach security-relevant headers to particular paths or file types are affected. An unauthenticated attacker who knows the path of a protected file can request it through a dot segment path and receive it without those headers, for example without Content-Disposition: attachment or a restrictive Content-Security-Policy that prevents uploaded HTML from rendering inline. The file itself is served unchanged. Applications that do not use path-specific header_rules are not affected.
Mitigation
- Update to a patched version of Rack in which
header_rulesare matched against the same normalized path used to serve the file. - Reject requests containing dot segments at a reverse proxy or application boundary.
- Do not rely solely on
Rack::Staticheader_rulesto prevent inline rendering of untrusted uploads; serve them from a separate origin.
Credit
- Reporter and Remediation developer
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 💎RubyGems | rack | all versions | 2.2.25bundle update rack --conservative |
| 💎RubyGems | rack | ≥ 3.0.0&&< 3.1.23 | 3.1.23bundle update rack --conservative |
| 💎RubyGems | rack | ≥ 3.2.0&&< 3.2.8 | 3.2.8bundle update rack --conservative |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for rack, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update rack to 2.2.25 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-125110 is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
Frequently Asked Questions
Is CVE-2026-125110 in your dependencies?
Find it across RubyGems, including transitive dependencies.