---
id: "CVE-2026-125110"
page: "https://infrastack.ai/live/CVE-2026-125110"
kind: "vulnerability"
aliases: ["CVE-2026-125110", "GHSA-wvg4-6p58-3gh3"]
title: "`Rack::Static` `header_rules` bypass via unnormalized dot segments in the request path."
severity: "medium"
cvss: 5.3
epss: null
exploited: false
status: "open"
category: "package"
products: [{"name": "rack", "fixed": ["2.2.25"], "affected": "< 2.2.25", "ecosystem": "rubygems"}, {"name": "rack", "fixed": ["3.1.23"], "affected": ">= 3.0, < 3.1.23", "ecosystem": "rubygems"}, {"name": "rack", "fixed": ["3.2.8"], "affected": ">= 3.2, < 3.2.8", "ecosystem": "rubygems"}]
ecosystems: ["rubygems"]
tags: ["cwe-180", "package", "rack", "rails", "ruby", "rubygems", "self-hosted"]
not_affected_if: ["managed-hosting", "no-header-rules", "static-export"]
published_at: "2026-10-30T02:18:56+00:00"
first_seen_at: "2026-11-09T22:53:30+00:00"
updated_at: "2026-11-09T22:56:36+00:00"
sources: [{"source": "ghsa-repo", "url": "https://github.com/rack/rack/security/advisories/GHSA-wvg4-6p58-3gh3", "first_seen_at": "2026-11-09T22:53:30+00:00"}, {"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-125110", "first_seen_at": "2026-11-10T00:28:47+00:00"}]
exploit_sources: []
---

# `Rack::Static` `header_rules` bypass via unnormalized dot segments in the request path.

Link for people: https://infrastack.ai/live/CVE-2026-125110 (this .md is for agents)

Rack::Static matches header_rules against a path that is only URL-decoded, while serving the normalized file, so dot-segment requests skip rules. An unauthenticated attacker can fetch a protected file without the security headers configured for it, such as Content-Disposition or a restrictive Content-Security-Policy.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- rubygems:rack affected < 2.2.25 fixed 2.2.25
- rubygems:rack affected >= 3.0, < 3.1.23 fixed 3.1.23
- rubygems:rack affected >= 3.2, < 3.2.8 fixed 3.2.8

## How to check

- Check the installed rack gem version: `bundle list rack` or look at `Gemfile.lock` for `rack`.
- Search your app config for `Rack::Static` and `header_rules`; if none are used, the issue does not apply.
- Check whether a reverse proxy already rejects dot segments in request paths.

## Fix

- rack `< 2.2.25`: move to `2.2.25`
- rack `>= 3.0, < 3.1.23`: move to `3.1.23`
- rack `>= 3.2, < 3.2.8`: move to `3.2.8`

## Timeline

- 2026-11-09T22:53:30+00:00 ghsa-repo https://github.com/rack/rack/security/advisories/GHSA-wvg4-6p58-3gh3
- 2026-11-10T00:28:47+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-125110

## Documents

- [advisory] Maintainer's advisory: github.com https://github.com/rack/rack/security/advisories/GHSA-wvg4-6p58-3gh3
- [fix] Patch: github.com https://github.com/rack/rack/commit/18a07fe553afb4d8a678d6a948cd6ba1e11e28be
- [fix] Patch: github.com https://github.com/rack/rack/commit/9d7f19484ffd5ed5e032678c26ee6eff96d3a0a3
- [fix] Patch: github.com https://github.com/rack/rack/commit/e88097ccb88be44d06d47b42daffe04929516ee4

## From the sources

## 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_rules` are 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::Static` `header_rules` to prevent inline rendering of untrusted uploads; serve them from a separate origin.

## Credit
* Reporter and Remediation developer

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
