Apr 2, 2026·4 min read·51 visits
Rack::Static evaluates security header rules against raw URL paths before decoding them. Requesting an encoded file extension (e.g., %2ejs) bypasses header rules (like CSP) while still serving the requested file.
A canonicalization vulnerability in the Rack Ruby gem's Rack::Static middleware allows attackers to bypass security header rules. By supplying URL-encoded paths, an attacker can evade pattern-matching logic while still retrieving the targeted static files.
Rack middleware uses Rack::Static to serve static files and apply security headers based on path patterns. The middleware evaluates these rules against the raw, unescaped PATH_INFO string extracted from the HTTP request.
A discrepancy exists because the underlying file-serving logic, typically handled by Rack::File, URI-decodes the path before accessing the filesystem. This canonicalization mismatch allows an attacker to manipulate the request path with URL encoding to evade the initial checks.
The flaw is tracked as CWE-180 (Incorrect Behavior Order: Validate Before Canonicalize). By encoding characters critical to pattern matching, such as replacing a file extension dot with %2E, an attacker bypasses the header rules but still retrieves the intended file.
The vulnerability originates in the Rack::Static#applicable_rules method located in lib/rack/static.rb. This method iterates through configured matching rules, including arrays of file extensions, strings, and regular expressions, to determine which HTTP headers apply to a given request.
During the evaluation phase, the path variable strictly contains the raw PATH_INFO value. If a developer defines a rule applying a Content-Security-Policy header to all .js files, the regex generated by the middleware literalizes the dot character.
When a request specifies an encoded extension like %2ejs, the exact string match fails against the regex expecting .js. The rules engine concludes no headers are required, while the subsequent file-serving layer decodes the path and successfully locates the file on disk.
The vulnerable implementation processes the raw path directly within the rule evaluation block. The regular expression dynamically created from array inputs expects literal dot characters preceding the file extension, leading to the mismatch when URL encoding is used.
def applicable_rules(path)
@header_rules.find_all do |rule, new_headers|
case rule
# ...
when Array
/\.(#{rule.join('|')})\z/.match?(path)
end
end
endThe patch addresses this by enforcing canonicalization prior to validation. The path variable is explicitly decoded using ::Rack::Utils.unescape_path(path) before any rule matching occurs.
def applicable_rules(path)
# Fix: Decode the path once before matching
path = ::Rack::Utils.unescape_path(path)
@header_rules.find_all do |rule, new_headers|
case rule
# ...
when Array
# Fix: Safely construct regex with union
/\.#{Regexp.union(rule)}\z/.match?(path)
end
end
endExploitation requires a target application utilizing Rack::Static to serve files while enforcing security rules based on file extensions or paths. The attacker must understand the applied rules and the location of the static assets.
The attacker crafts an HTTP request where the file extension separator is URL-encoded. For example, instead of requesting /js/app.js, the attacker requests /js/app%2ejs.
The middleware processes /js/app%2ejs, failing to match the js header rule. The file server then decodes the path to /js/app.js and serves the file, bypassing the security controls.
The immediate impact is the circumvention of intended security policies applied to static files. This primarily affects defensive headers such as Content-Security-Policy (CSP), X-Frame-Options, and Cache-Control.
Bypassing CSP on JavaScript or HTML files facilitates Cross-Site Scripting (XSS) if the served files process untrusted input. The lack of X-Frame-Options exposes the application to UI redressing and Clickjacking attacks.
The vulnerability carries a CVSS v3.1 score of 5.3 (Medium), reflecting the requirement for chaining with other flaws to achieve direct compromise. The confidentiality, integrity, and availability of the underlying server infrastructure remain unaffected.
Upgrading the Rack gem is the primary and complete remediation for this vulnerability. Administrators must update deployments to versions 2.2.23, 3.1.21, or 3.2.6.
If an immediate upgrade is unfeasible, administrators can deploy defensive configuration rules at the reverse proxy or web server layer. Configuring Nginx or Apache to reject requests containing URL-encoded dots (%2E or %2e) in static asset paths mitigates the bypass.
After applying the patch, security teams should verify the fix by requesting statically served files using encoded extensions. A successful remediation will apply the configured security headers uniformly across standard and encoded path requests.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Rack (Ruby Gem) Rack | < 2.2.23 | 2.2.23 |
Rack (Ruby Gem) Rack | >= 3.0.0.beta1, < 3.1.21 | 3.1.21 |
Rack (Ruby Gem) Rack | >= 3.2.0, < 3.2.6 | 3.2.6 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-180 |
| CVSS Score | 5.3 |
| Attack Vector | Network |
| Impact | Security Header Bypass |
| Exploit Status | None |
| CISA KEV | False |
Incorrect Behavior Order: Validate Before Canonicalize
An algorithmic complexity vulnerability in the python-sqlparse library allows remote, unauthenticated attackers to cause a Denial of Service (DoS) via resource exhaustion. By transmitting a carefully constructed SQL statement containing deeply nested structures, an attacker can trigger quadratic CPU consumption within the parsing engine. This behavior bypasses the built-in depth limits because the performance degradation occurs during the initial recursive tree construction, causing the application process to hang.
A critical vulnerability exists in the atomic-agents-stack package up to version 1.0.0. The HTTP Model Context Protocol (MCP) server-registry backend factory retrieves catalog metadata over cleartext HTTP by default. Because these catalogs define execution parameters ('command' and 'args') for local stdio subprocesses, a network-positioned attacker can intercept the cleartext traffic and inject arbitrary commands. This results in arbitrary remote code execution on the agent host system without requiring user interaction.
A high-severity vulnerability in the atomic-agents-stack framework allows complete bypass of cost-cap guardrails during parallel model execution when utilizing unlisted, local, or self-hosted models.
A security vulnerability in the Go library software.sslmate.com/src/go-pkcs12 allows remote attackers to bypass password-based integrity verification. By crafting a PKCS#12 file with an excessively short KeyLength parameter in the PBMAC1 configuration, the derived MAC key space collapses, allowing an attacker to forge arbitrary certificate structures and private keys that are incorrectly verified as valid.
A workspace boundary bypass vulnerability exists in the Chrome DevTools for Agents (chrome-devtools-mcp) Model Context Protocol (MCP) server from version 0.24.0 up to 1.1.0. The vulnerability allows an agent or malicious workspace containing symbolic links to read or modify arbitrary files outside the configured project workspace root directory. This occurs because the path validation function resolves paths lexically rather than physically.
A high-severity security vulnerability exists in 9Router, an AI router and token saver dashboard. When dashboard authentication features are disabled or left in default configurations, the application exposes administrative testing routines directly to the public internet. Unauthenticated network adversaries can exploit the OIDC configuration validation endpoint to initiate arbitrary HTTP requests, routing unauthorized traffic to local loops, adjacent container ports, and cloud resource metadata interfaces.