CWE-180
AllowedIncorrect Behavior Order: Validate Before Canonicalize
Abstraction: Variant · Status: Draft
The product validates input before it is canonicalized, which prevents the product from detecting data that becomes invalid after the canonicalization step.
33 vulnerabilities reference this CWE, most recent first.
GHSA-Q4QF-9J86-F5MH
Vulnerability from github – Published: 2026-04-02 18:44 – Updated: 2026-05-13 15:20Summary
Rack::Static#applicable_rules evaluates several header_rules types against the raw URL-encoded PATH_INFO, while the underlying file-serving path is decoded before the file is served. As a result, a request for a URL-encoded variant of a static path can serve the same file without the headers that header_rules were intended to apply.
In deployments that rely on Rack::Static to attach security-relevant response headers to static content, this can allow an attacker to bypass those headers by requesting an encoded form of the path.
Details
Rack::Static#applicable_rules matches rule types such as :fonts, Array, and Regexp directly against the incoming PATH_INFO. For example:
when :fonts
/\.(?:ttf|otf|eot|woff2|woff|svg)\z/.match?(path)
when Array
/\.(#{rule.join('|')})\z/.match?(path)
when Regexp
rule.match?(path)
These checks operate on the raw request path. If the request contains encoded characters such as %2E in place of ., the rule may fail to match even though the file path is later decoded and served successfully by the static file server.
For example, both of the following requests may resolve to the same file on disk:
/fonts/test.woff
/fonts/test%2Ewoff
but only the unencoded form may receive the headers configured through header_rules.
This creates a canonicalization mismatch between the path used for header policy decisions and the path ultimately used for file serving.
Impact
Applications that rely on Rack::Static header_rules to apply security-relevant headers to static files may be affected.
In affected deployments, an attacker can request an encoded variant of a static file path and receive the same file without the intended headers. Depending on how header_rules are used, this may bypass protections such as clickjacking defenses, content restrictions, or other response policies applied to static content.
The practical impact depends on the configured rules and the types of files being served. If header_rules are only used for non-security purposes such as caching, the issue may have limited security significance.
Mitigation
- Update to a patched version of Rack that applies
header_rulesto a decoded path consistently with static file resolution. - Do not rely solely on
Rack::Staticheader_rulesfor security-critical headers where encoded path variants may reach the application. - Prefer setting security headers at the reverse proxy or web server layer so they apply consistently to both encoded and unencoded path forms.
- Normalize or reject encoded path variants for static content at the edge, where feasible.
{
"affected": [
{
"package": {
"ecosystem": "RubyGems",
"name": "rack"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.2.23"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "RubyGems",
"name": "rack"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0.beta1"
},
{
"fixed": "3.1.21"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "RubyGems",
"name": "rack"
},
"ranges": [
{
"events": [
{
"introduced": "3.2.0"
},
{
"fixed": "3.2.6"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-34786"
],
"database_specific": {
"cwe_ids": [
"CWE-180"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-02T18:44:49Z",
"nvd_published_at": "2026-04-02T17:16:25Z",
"severity": "MODERATE"
},
"details": "## Summary\n\n`Rack::Static#applicable_rules` evaluates several `header_rules` types against the raw URL-encoded `PATH_INFO`, while the underlying file-serving path is decoded before the file is served. As a result, a request for a URL-encoded variant of a static path can serve the same file without the headers that `header_rules` were intended to apply.\n\nIn deployments that rely on `Rack::Static` to attach security-relevant response headers to static content, this can allow an attacker to bypass those headers by requesting an encoded form of the path.\n\n## Details\n\n`Rack::Static#applicable_rules` matches rule types such as `:fonts`, `Array`, and `Regexp` directly against the incoming `PATH_INFO`. For example:\n\n```ruby\nwhen :fonts\n /\\.(?:ttf|otf|eot|woff2|woff|svg)\\z/.match?(path)\nwhen Array\n /\\.(#{rule.join(\u0027|\u0027)})\\z/.match?(path)\nwhen Regexp\n rule.match?(path)\n```\n\nThese checks operate on the raw request path. If the request contains encoded characters such as `%2E` in place of `.`, the rule may fail to match even though the file path is later decoded and served successfully by the static file server.\n\nFor example, both of the following requests may resolve to the same file on disk:\n\n```text\n/fonts/test.woff\n/fonts/test%2Ewoff\n```\n\nbut only the unencoded form may receive the headers configured through `header_rules`.\n\nThis creates a canonicalization mismatch between the path used for header policy decisions and the path ultimately used for file serving.\n\n## Impact\n\nApplications that rely on `Rack::Static` `header_rules` to apply security-relevant headers to static files may be affected.\n\nIn affected deployments, an attacker can request an encoded variant of a static file path and receive the same file without the intended headers. Depending on how `header_rules` are used, this may bypass protections such as clickjacking defenses, content restrictions, or other response policies applied to static content.\n\nThe practical impact depends on the configured rules and the types of files being served. If `header_rules` are only used for non-security purposes such as caching, the issue may have limited security significance.\n\n## Mitigation\n\n* Update to a patched version of Rack that applies `header_rules` to a decoded path consistently with static file resolution.\n* Do not rely solely on `Rack::Static` `header_rules` for security-critical headers where encoded path variants may reach the application.\n* Prefer setting security headers at the reverse proxy or web server layer so they apply consistently to both encoded and unencoded path forms.\n* Normalize or reject encoded path variants for static content at the edge, where feasible.",
"id": "GHSA-q4qf-9j86-f5mh",
"modified": "2026-05-13T15:20:50Z",
"published": "2026-04-02T18:44:49Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/rack/rack/security/advisories/GHSA-q4qf-9j86-f5mh"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34786"
},
{
"type": "PACKAGE",
"url": "https://github.com/rack/rack"
},
{
"type": "WEB",
"url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/rack/CVE-2026-34786.yml"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "Rack:: Static header_rules bypass via URL-encoded paths"
}
GHSA-V2WJ-Q39Q-566R
Vulnerability from github – Published: 2026-04-06 18:03 – Updated: 2026-04-07 22:16Summary
The contents of files that are specified by server.fs.deny can be returned to the browser.
Impact
Only apps that match the following conditions are affected:
- explicitly exposes the Vite dev server to the network (using
--hostorserver.hostconfig option) - the sensitive file exists in the allowed directories specified by
server.fs.allow - the sensitive file is denied with a pattern that matches a file by
server.fs.deny
Details
On the Vite dev server, files that should be blocked by server.fs.deny (e.g., .env, *.crt) can be retrieved with HTTP 200 responses when query parameters such as ?raw, ?import&raw, or ?import&url&inline are appended.
PoC
- Start the dev server:
pnpm exec vite root --host 127.0.0.1 --port 5175 --strictPort - Confirm that
server.fs.denyis enforced (expect 403):curl -i http://127.0.0.1:5175/src/.env | head -n 20 - Confirm that the same files can be retrieved with query parameters (expect 200):
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 8.0.4"
},
"package": {
"ecosystem": "npm",
"name": "vite"
},
"ranges": [
{
"events": [
{
"introduced": "8.0.0"
},
{
"fixed": "8.0.5"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 7.3.1"
},
"package": {
"ecosystem": "npm",
"name": "vite"
},
"ranges": [
{
"events": [
{
"introduced": "7.1.0"
},
{
"fixed": "7.3.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-39364"
],
"database_specific": {
"cwe_ids": [
"CWE-180",
"CWE-284"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-06T18:03:32Z",
"nvd_published_at": "2026-04-07T20:16:30Z",
"severity": "HIGH"
},
"details": "### Summary\n\nThe contents of files that are specified by [`server.fs.deny`](https://vite.dev/config/server-options#server-fs-deny) can be returned to the browser.\n\n### Impact\n\nOnly apps that match the following conditions are affected:\n\n- explicitly exposes the Vite dev server to the network (using `--host` or [`server.host` config option](https://vitejs.dev/config/server-options.html#server-host))\n- the sensitive file exists in the allowed directories specified by [`server.fs.allow`](https://vite.dev/config/server-options#server-fs-allow)\n- the sensitive file is denied with a pattern that matches a file by [`server.fs.deny`](https://vite.dev/config/server-options#server-fs-deny)\n\n### Details\n\nOn the Vite dev server, files that should be blocked by `server.fs.deny` (e.g., `.env`, `*.crt`) can be retrieved with HTTP 200 responses when query parameters such as `?raw`, `?import\u0026raw`, or `?import\u0026url\u0026inline` are appended.\n\n### PoC\n\n1. Start the dev server: `pnpm exec vite root --host 127.0.0.1 --port 5175 --strictPort`\n2. Confirm that `server.fs.deny` is enforced (expect 403): `curl -i http://127.0.0.1:5175/src/.env | head -n 20`\n \u003cimg width=\"3944\" height=\"1092\" alt=\"image\" src=\"https://github.com/user-attachments/assets/ecb9f2e0-e08f-4ac7-b194-e0f988c4cd4f\" /\u003e\n3. Confirm that the same files can be retrieved with query parameters (expect 200):\n \u003cimg width=\"2014\" height=\"373\" alt=\"image\" src=\"https://github.com/user-attachments/assets/76bc2a6a-44f4-4161-ae47-eab5ae0c04a8\" /\u003e",
"id": "GHSA-v2wj-q39q-566r",
"modified": "2026-04-07T22:16:17Z",
"published": "2026-04-06T18:03:32Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/vitejs/vite/security/advisories/GHSA-v2wj-q39q-566r"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-39364"
},
{
"type": "WEB",
"url": "https://github.com/vitejs/vite/pull/22160"
},
{
"type": "WEB",
"url": "https://github.com/vitejs/vite/commit/a9a3df299378d9cbc5f069e3536a369f8188c8ff"
},
{
"type": "PACKAGE",
"url": "https://github.com/vitejs/vite"
},
{
"type": "WEB",
"url": "https://github.com/vitejs/vite/releases/tag/v7.3.2"
},
{
"type": "WEB",
"url": "https://github.com/vitejs/vite/releases/tag/v8.0.5"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Vite: `server.fs.deny` bypassed with queries"
}
GHSA-XPCF-PG52-R92G
Vulnerability from github – Published: 2026-04-08 00:17 – Updated: 2026-04-24 21:06Summary
ipRestriction() does not canonicalize IPv4-mapped IPv6 client addresses (e.g. ::ffff:127.0.0.1) before applying IPv4 allow or deny rules. In environments such as Node.js dual-stack, this can cause IPv4 rules to fail to match, leading to unintended authorization behavior.
Details
The middleware classifies client addresses based on their textual form. Addresses containing ":" are treated as IPv6, including IPv4-mapped IPv6 addresses such as ::ffff:127.0.0.1. These addresses are not normalized to IPv4 before matching.
As a result:
- IPv4 static rules (e.g.
127.0.0.1) do not match because the raw string differs - IPv4 CIDR rules (e.g.
127.0.0.0/8,10.0.0.0/8) are skipped because the address is treated as IPv6
For example, with:
denyList: ['127.0.0.1']
a request from 127.0.0.1 may be represented as ::ffff:127.0.0.1 and bypass the deny rule.
This behavior commonly occurs in Node.js environments where IPv4 clients are exposed as IPv4-mapped IPv6 addresses.
Impact
Applications that rely on IPv4-based ipRestriction() rules may incorrectly allow or deny requests.
In affected deployments, a denied IPv4 client may bypass access restrictions. Conversely, legitimate clients may be rejected when using IPv4 allow lists.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "hono"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.12.12"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-39409"
],
"database_specific": {
"cwe_ids": [
"CWE-180"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-08T00:17:14Z",
"nvd_published_at": "2026-04-08T15:16:14Z",
"severity": "MODERATE"
},
"details": "## Summary\n\n`ipRestriction()` does not canonicalize IPv4-mapped IPv6 client addresses (e.g. `::ffff:127.0.0.1`) before applying IPv4 allow or deny rules. In environments such as Node.js dual-stack, this can cause IPv4 rules to fail to match, leading to unintended authorization behavior.\n\n## Details\n\nThe middleware classifies client addresses based on their textual form. Addresses containing \"`:`\" are treated as IPv6, including IPv4-mapped IPv6 addresses such as `::ffff:127.0.0.1`. These addresses are not normalized to IPv4 before matching.\n\nAs a result:\n\n* IPv4 static rules (e.g. `127.0.0.1`) do not match because the raw string differs\n* IPv4 CIDR rules (e.g. `127.0.0.0/8`, `10.0.0.0/8`) are skipped because the address is treated as IPv6\n\nFor example, with:\n\n`denyList: [\u0027127.0.0.1\u0027]`\n\na request from `127.0.0.1` may be represented as `::ffff:127.0.0.1` and bypass the deny rule.\n\nThis behavior commonly occurs in Node.js environments where IPv4 clients are exposed as IPv4-mapped IPv6 addresses.\n\n## Impact\n\nApplications that rely on IPv4-based `ipRestriction()` rules may incorrectly allow or deny requests.\n\nIn affected deployments, a denied IPv4 client may bypass access restrictions. Conversely, legitimate clients may be rejected when using IPv4 allow lists.",
"id": "GHSA-xpcf-pg52-r92g",
"modified": "2026-04-24T21:06:13Z",
"published": "2026-04-08T00:17:14Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/honojs/hono/security/advisories/GHSA-xpcf-pg52-r92g"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-39409"
},
{
"type": "WEB",
"url": "https://github.com/honojs/hono/commit/48fa2233bc092f650119f42df043050737cabf39"
},
{
"type": "PACKAGE",
"url": "https://github.com/honojs/hono"
},
{
"type": "WEB",
"url": "https://github.com/honojs/hono/releases/tag/v4.12.12"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Hono has incorrect IP matching in ipRestriction() for IPv4-mapped IPv6 addresses"
}
Mitigation MIT-20
Strategy: Input Validation
Inputs should be decoded and canonicalized to the application's current internal representation before being validated (CWE-180). Make sure that the application does not decode the same input twice (CWE-174). Such errors could be used to bypass allowlist validation schemes by introducing dangerous inputs after they have been checked.
CAPEC-267: Leverage Alternate Encoding
An adversary leverages the possibility to encode potentially harmful input or content used by applications such that the applications are ineffective at validating this encoding standard.
CAPEC-3: Using Leading 'Ghost' Character Sequences to Bypass Input Filters
Some APIs will strip certain leading characters from a string of parameters. An adversary can intentionally introduce leading "ghost" characters (extra characters that don't affect the validity of the request at the API layer) that enable the input to pass the filters and therefore process the adversary's input. This occurs when the targeted API will accept input data in several syntactic forms and interpret it in the equivalent semantic way, while the filter does not take into account the full spectrum of the syntactic forms acceptable to the targeted API.
CAPEC-71: Using Unicode Encoding to Bypass Validation Logic
An attacker may provide a Unicode string to a system component that is not Unicode aware and use that to circumvent the filter or cause the classifying mechanism to fail to properly understanding the request. That may allow the attacker to slip malicious data past the content filter and/or possibly cause the application to route the request incorrectly.
CAPEC-78: Using Escaped Slashes in Alternate Encoding
This attack targets the use of the backslash in alternate encoding. An adversary can provide a backslash as a leading character and causes a parser to believe that the next character is special. This is called an escape. By using that trick, the adversary tries to exploit alternate ways to encode the same character which leads to filter problems and opens avenues to attack.
CAPEC-79: Using Slashes in Alternate Encoding
This attack targets the encoding of the Slash characters. An adversary would try to exploit common filtering problems related to the use of the slashes characters to gain access to resources on the target host. Directory-driven systems, such as file systems and databases, typically use the slash character to indicate traversal between directories or other container components. For murky historical reasons, PCs (and, as a result, Microsoft OSs) choose to use a backslash, whereas the UNIX world typically makes use of the forward slash. The schizophrenic result is that many MS-based systems are required to understand both forms of the slash. This gives the adversary many opportunities to discover and abuse a number of common filtering problems. The goal of this pattern is to discover server software that only applies filters to one version, but not the other.
CAPEC-80: Using UTF-8 Encoding to Bypass Validation Logic
This attack is a specific variation on leveraging alternate encodings to bypass validation logic. This attack leverages the possibility to encode potentially harmful input in UTF-8 and submit it to applications not expecting or effective at validating this encoding standard making input filtering difficult. UTF-8 (8-bit UCS/Unicode Transformation Format) is a variable-length character encoding for Unicode. Legal UTF-8 characters are one to four bytes long. However, early version of the UTF-8 specification got some entries wrong (in some cases it permitted overlong characters). UTF-8 encoders are supposed to use the "shortest possible" encoding, but naive decoders may accept encodings that are longer than necessary. According to the RFC 3629, a particularly subtle form of this attack can be carried out against a parser which performs security-critical validity checks against the UTF-8 encoded form of its input, but interprets certain illegal octet sequences as characters.