Sep 30, 2026·4 min read·3 visits
An incorrect sequence of case folding and percent-decoding in fast-uri allows attackers to bypass case-sensitive domain filters using percent-encoded uppercase hostnames in scheme-relative URLs.
CVE-2026-86472 is a validation bypass vulnerability in fast-uri (a high-performance RFC 3986 URI toolbox heavily used by popular Node.js frameworks like Fastify and validation libraries like AJV). The vulnerability stems from improper handling of case sensitivity (CWE-178) due to an incorrect order of operations during hostname canonicalization in scheme-relative URLs. An attacker can leverage percent-encoded uppercase characters within scheme-relative URLs to bypass domain blocklists/allowlists in downstream applications. Because hostname resolution in DNS and HTTP is case-insensitive, the bypassed host representation still routes to the target destination, resulting in potential Server-Side Request Forgery (SSRF) or security control bypasses.
The vulnerability CVE-2026-86472 is an improper handling of case sensitivity (CWE-178) within the fast-uri library, an RFC 3986 compliant URI parser written for Node.js environments. The library serves as a critical performance-oriented dependency for parsing tasks in popular web frameworks and validation engines, including Fastify and AJV. The attack surface is exposed primarily when downstream systems process, validate, or perform routing decisions on user-supplied URLs.
Because hostname matching and resolving are inherently case-insensitive, a vulnerability arises when parsing and security filtering do not normalize capitalization in an identical fashion. The flaw allows external actors to submit specifically formatted URIs that bypass standard string-matching list validations, while still resolving to targeted servers. This discrepancy can compromise validation barriers, potentially permitting unintended network exposure or unauthorized access paths.
The flaw is located within the canonicalization workflow of the parser function (parseWithStatus inside index.js), specifically during the handling of hostnames in scheme-relative URLs. RFC 3986 requires that registered names (hostnames) be case-insensitive and folded to lowercase. It also specifies that percent-encoded unreserved characters, such as %41 representing 'A', should be decoded to their literal equivalents.
In the vulnerable codebase, the host lowercasing fold was executed prior to the percent-decoding sequence. Consequently, the percent-encoding identifier %41 remained unchanged by the lowercasing pass since it does not contain uppercase alphabetical characters. When the subsequent percent-decoding step ran, it converted %41 into its literal ASCII representation 'A', leaving an uppercase character in the parsed hostname.
This parsed output is structurally invalid according to lowercase normalization requirements, yet resolves correctly at the DNS or network routing level. Furthermore, this canonicalization logic was conditionally executed only within scheme-specific validation blocks. When parsing a scheme-relative URI (e.g., //%41.com), the absence of a scheme bypassed the secondary normalization checks, preserving the casing inconsistency.
The vulnerable logic in index.js checks for a scheme handler before applying host percent-decoding and normalization. This design omitted scheme-relative URLs from consistent parsing:
if (!schemeHandler || (schemeHandler && !schemeHandler.skipNormalize)) {
if (uri.indexOf('%') !== -1) {
if (parsed.host !== undefined && !malformedIPLiteral) {
const host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true)
parsed.host = reescapeHostDelimiters(host, isIP)
}
}
}The fix extracts the percent-decoding check outside of the scheme handler validation block, executing it unconditionally. The normalization process was also reordered to ensure case folding occurs after decoding:
if (uri.indexOf('%') !== -1 && parsed.host !== undefined && !malformedIPLiteral) {
let host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true)
if (!isIP) {
// Fold reg-name case after decoding unreserved octets.
host = normalizePercentEncoding(host.toLowerCase())
}
parsed.host = reescapeHostDelimiters(host, isIP)
}This ensures that any percent-encoded unreserved characters are first decoded to their literal forms, then folded to lowercase, and finally normalized to restore valid percent-escapes.
Exploitation requires that an application parses an input URI, validates the parsed host against an allowlist or denylist using case-sensitive operations, and subsequently uses the original or parsed URL to make an HTTP request. The attacker crafts a scheme-relative URI containing percent-encoded uppercase letters matching characters in a restricted domain.
When the application evaluates A.com against a case-sensitive blocklist containing a.com, the match fails, allowing the request to proceed. The downstream HTTP client then performs case-insensitive resolution, routing the request to a.com anyway.
The primary risk associated with this vulnerability is the evasion of domain-based access controls, leading to security filter bypasses such as Server-Side Request Forgery (SSRF). If an application restricts outbound connections using an allowlist parsed by fast-uri, an attacker can bypass this protection to access internal endpoints.
This vulnerability has a CVSS v3.1 base score of 4.8 (Medium), reflecting high attack complexity and low impact on confidentiality and integrity. No active exploitation has been observed, and the exploit status remains at proof-of-concept level.
Remediation requires upgrading fast-uri to version 2.4.7, 3.1.8, or 4.1.5, depending on the active branch. These versions contain the refactored parsing logic that resolves the order-of-operations conflict.
Where immediate upgrades are not feasible, developers must manually fold parsed hostnames to lowercase before performing string validation. This mitigation prevents differential interpretations between the application's business logic and the network layer.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
fast-uri fastify | < 2.4.7 | 2.4.7 |
fast-uri fastify | 3.0.0 - 3.1.7 | 3.1.8 |
fast-uri fastify | 4.0.0 - 4.1.4 | 4.1.5 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-178 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 4.8 |
| EPSS Score | 0.00253 |
| Exploit Status | poc |
| CISA KEV Status | Not Listed |
The software performs a case-sensitive comparison or manipulation of an identifier that is meant to be case-insensitive, leading to security filter evasion.
CVE-2026-101894 is a critical path traversal vulnerability in @xhmikosr/decompress before versions 10.2.2 and 11.1.4, stemming from an incomplete hardening bypass of CVE-2026-53486 where static lexical containment checks fail to detect kernel-level resolution of crafted symlink chains, allowing arbitrary local file modification and execution.
A security-critical desynchronization vulnerability exists in fast-uri versions 4.1.3 and 4.1.4. Due to incorrect order-of-operations, the mailto scheme parser validates raw percent-encoded parameter keys instead of normalized keys, but subsequently decodes and writes them into a generic headers object. When the parsed URI is serialized, these keys are re-emitted literally, allowing attackers to bypass validation boundaries and smuggle unauthorized recipients, subjects, or body parameters in downstream mailing applications.
An unauthenticated remote attacker can crash NestJS microservices utilizing TCP or RabbitMQ transport layers. The vulnerability exists due to recursive serialization of deeply nested message patterns using JSON.stringify, leading to a RangeError and process termination.
A resource management vulnerability in the Undici HTTP client (CWE-772) occurs when the retry interceptor receives a partial body payload followed by a non-retryable response error on a subsequent connection attempt, resulting in orphaned streams and potential Denial of Service (DoS).
A vulnerability in PyJWT's JWK Set parsing logic allows a malformed RSA key to trigger an unhandled ValueError, leading to an application-wide or request-level Denial of Service.
An uncontrolled recursion vulnerability exists in Nodemailer versions up to and including 10.0.1. When parsing recipient email addresses, recursively nested arrays bypass the parser's depth limit, resulting in V8 call stack exhaustion and immediate synchronous process termination.