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.
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.
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.
header_rules are matched against the same normalized path used to serve the file.Rack::Static header_rules to prevent inline rendering of untrusted uploads; serve them from a separate origin.{
"cwe_ids": [
"CWE-180"
],
"github_reviewed": true,
"github_reviewed_at": "2026-11-10T18:50:07Z",
"nvd_published_at": "2026-11-09T22:18:42Z",
"severity": "MODERATE"
}