CVE-2026-34786
Executive Summary
CVE-2026-34786 is a vulnerability in the Rack Ruby web server interface that allows an attacker to bypass security-relevant response headers applied via Rack::Static's header_rules configuration. The flaw arises because Rack::Static#applicable_rules evaluates header rules against the raw URL-encoded PATH_INFO, while the actual file-serving path is decoded before serving. This discrepancy means that a request for a URL-encoded variant of a static path can serve the same file without the intended headers. In deployments relying on Rack::Static to attach headers like Content-Security-Policy, X-Frame-Options, or Strict-Transport-Security to static content, an attacker can bypass these protections by requesting an encoded form of the path. The vulnerability has a CVSS score of 5.3 (Medium) and is patched in versions 2.2.23, 3.1.21, and 3.2.6.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability affects the Rack gem, a core component of the Ruby ecosystem and the foundation for many Ruby web frameworks, including Ruby on Rails. The Rack gem is distributed via RubyGems and is a transitive dependency for thousands of Ruby applications. Organizations using Ruby web servers should audit their Gemfile.lock for affected versions and update immediately. The supply chain risk is moderate, as the vulnerability is patched and no public exploits are available, but the widespread use of Rack means many applications could be affected.
CVSS Breakdown & Threat Level
- CVSS Score: 5.3 (Medium)
- Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
- Attack Vector: Network (AV:N)
- Attack Complexity: Low (AC:L)
- Privileges Required: None (PR:N)
- User Interaction: None (UI:N)
- Scope: Unchanged (S:U)
- Confidentiality Impact: None (C:N)
- Integrity Impact: Low (I:L) – Security headers can be bypassed, potentially enabling other attacks like XSS or clickjacking.
- Availability Impact: None (A:N)
Threat Level: Medium. The vulnerability allows bypassing security headers but does not directly enable code execution or data theft. However, it can be chained with other vulnerabilities (e.g., XSS) to increase impact.
Deep Dive & Mechanics
The vulnerability lies in the Rack::Static middleware, which is used to serve static files and optionally attach response headers based on rules defined in header_rules. The applicable_rules method evaluates these rules against the raw PATH_INFO from the request, which may be URL-encoded. However, when the actual file is served, the path is decoded (e.g., %2e%2e becomes ..). This mismatch allows an attacker to request a URL-encoded version of a static path, bypassing the header rules.
For example, if a rule is configured to attach X-Frame-Options: DENY to all .html files, an attacker could request %2e%2e/index.html (URL-encoded ../index.html). The applicable_rules method would see the raw encoded path and fail to match the rule, but the file server would decode the path and serve index.html without the header.
This is a classic encoding/decoding mismatch vulnerability (CWE-172: Encoding Error). The fix ensures that header rules are evaluated against the decoded PATH_INFO, aligning the rule evaluation with the actual file-serving behavior.
Vulnerable vs. Patched Code
Vulnerable Code (Rack::Static#applicable_rules):
def applicable_rules(request, headers)
path_info = request.path_info # Raw URL-encoded PATH_INFO
@header_rules.each do |rule, rule_headers|
case rule
when :all
headers.merge!(rule_headers)
when String
headers.merge!(rule_headers) if path_info == rule
when Regexp
headers.merge!(rule_headers) if path_info.match?(rule)
when Proc
headers.merge!(rule_headers) if rule.call(path_info)
end
end
headers
end
Patched Code (Rack::Static#applicable_rules):
def applicable_rules(request, headers)
path_info = request.path_info
# Decode the path_info before evaluating rules
decoded_path_info = URI.decode_www_form_component(path_info)
@header_rules.each do |rule, rule_headers|
case rule
when :all
headers.merge!(rule_headers)
when String
headers.merge!(rule_headers) if decoded_path_info == rule
when Regexp
headers.merge!(rule_headers) if decoded_path_info.match?(rule)
when Proc
headers.merge!(rule_headers) if rule.call(decoded_path_info)
end
end
headers
end
The key change is the addition of URI.decode_www_form_component(path_info) to decode the path before rule evaluation.
Exploitation & Lab Setup
Red Team
Prerequisites:
- A Ruby web application using Rack::Static with
header_rulesconfigured (e.g., to attach security headers to static files). - The application must be running an unpatched version of Rack (< 2.2.23, < 3.1.21, < 3.2.6).
Exploitation Steps:
- Identify a static file that should have security headers (e.g.,
/index.htmlwithX-Frame-Options: DENY). - Craft a URL-encoded request for the same file, e.g.,
/%2e%2e/index.html(URL-encoded../index.html). - Send the request using
curl:curl -v "http://target.com/%2e%2e/index.html" - Observe that the response lacks the expected security headers (e.g.,
X-Frame-Optionsis missing).
Example Exploit Script (Python):
import requests
target = "http://target.com"
encoded_path = "/%2e%2e/index.html"
response = requests.get(target + encoded_path)
print("Headers:", response.headers)
# Check for missing security headers
if "X-Frame-Options" not in response.headers:
print("Vulnerable: X-Frame-Options header bypassed")
Blue Team
Detection:
- Monitor for requests containing URL-encoded path traversal sequences (e.g.,
%2e%2e,%2f,%5c) targeting static files. - Look for discrepancies between the requested path and the served file (e.g., a request for
/%2e%2e/index.htmlservingindex.html). - Use the detection rules provided in the Detection Engineering section.
Mitigation:
- Immediately update Rack to version 2.2.23, 3.1.21, or 3.2.6.
- As a temporary workaround, implement a middleware that decodes
PATH_INFObefore passing it toRack::Static. - Review and harden
header_rulesconfigurations to ensure they are not the sole defense against attacks.
Indicators of Compromise (IOCs)
- Network IOCs:
- HTTP requests with URL-encoded path traversal sequences (e.g.,
%2e%2e,%2f,%5c) in the URI. - Responses from static files missing expected security headers (e.g.,
X-Frame-Options,Content-Security-Policy,Strict-Transport-Security).
- HTTP requests with URL-encoded path traversal sequences (e.g.,
- Log IOCs:
- Web server logs showing requests like
GET /%2e%2e/index.html HTTP/1.1with a 200 response. - Application logs showing
Rack::Staticserving files without applying header rules.
- Web server logs showing requests like
- File IOCs:
- No specific file-based IOCs, as this is a logic flaw in the middleware.
Detection Engineering
YARA Rule
rule CVE_2026_34786_Rack_Static_Header_Bypass {
meta:
description = "Detects Rack::Static header bypass via URL-encoded paths"
author = "Valters IT"
date = "2026-01-01"
reference = "CVE-2026-34786"
severity = "medium"
strings:
$s1 = "applicable_rules" ascii nocase
$s2 = "path_info" ascii nocase
$s3 = "header_rules" ascii nocase
$s4 = "URI.decode_www_form_component" ascii nocase
condition:
all of ($s1, $s2, $s3) and not $s4
}
Sigma Rule
title: CVE-2026-34786 - Rack::Static Header Bypass via URL-Encoded Path
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects HTTP requests with URL-encoded path traversal sequences targeting static files, indicating potential exploitation of CVE-2026-34786.
author: Valters IT
date: 2026-01-01
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-34786
logsource:
category: webserver
product: apache
service: http
detection:
selection:
cs-uri-query|contains:
- '%2e%2e'
- '%2f'
- '%5c'
condition: selection
falsepositives:
- Legitimate use of URL-encoded characters in paths (rare)
level: medium
Suricata Rule
alert http any any -> any any (msg:"CVE-2026-34786 - Rack::Static Header Bypass via URL-Encoded Path"; flow:to_server,established; content:"%2e%2e"; http_uri; classtype:attempted-recon; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Update Rack to version 2.2.23, 3.1.21, or 3.2.6.
- For Ruby on Rails applications, update the
rackgem in your Gemfile:gem 'rack', '>= 2.2.23' - Run
bundle update rackto apply the update.
- For Ruby on Rails applications, update the
- If immediate patching is not possible, implement a temporary workaround by adding a middleware that decodes
PATH_INFObefore it reachesRack::Static:class DecodePathInfoMiddleware def initialize(app) @app = app end def call(env) env['PATH_INFO'] = URI.decode_www_form_component(env['PATH_INFO']) @app.call(env) end end - Review all
header_rulesconfigurations and ensure they are not the sole defense against attacks. Combine with other security measures like WAF rules.
Long-Term Measures:
- Implement regular dependency scanning for Ruby gems (e.g., using
bundler-auditorDependabot). - Conduct security reviews of middleware configurations, especially those handling path encoding.
- Monitor for similar encoding/decoding mismatches in other parts of the application.
Valters IT
DevSecOps & Cyber Threat Intelligence Expert
{/* [Security Hash: 30EED7953260B1FF83D4EFC8] */}