Sep 2, 2026·7 min read·3 visits
The fast-uri library's IPv6 parser silently normalises invalid IP literals like [::not-valid] to [::] (the unspecified loopback address). Attackers exploit this parser differential to bypass security blocklists, redirecting outbound HTTP requests to internal networks or local services.
A critical parser differential vulnerability in the Node.js fast-uri library allows unauthenticated remote attackers to bypass address-validation filters and perform Server-Side Request Forgery (SSRF). The library fails to validate complete IPv6 grammar inside bracketed literals, silently truncating invalid trailing characters and normalising malformed hosts into valid loopback or private addresses.
The fast-uri library is an RFC 3986-compliant URI parsing toolbox designed for Node.js environments. It serves as a performance-optimized utility within the Fastify ecosystem. Because it lacks external dependencies, many downstream packages rely on its parsing and normalization logic to validate outbound requests, proxies, and redirects.
This security vulnerability arises from a custom parser designed to handle bracketed IPv6 literals (such as [::1]). Instead of enforcing a strict grammar validation on the contents inside the brackets, the parser sequentializes character processing. When it encounters invalid trailing text, it fails to throw an exception or flag an error. Instead, the parser silently discards the malformed trailing payload and normalizes the parsed host to a different, valid IP address.
This behavior establishes a classic parser differential vulnerability. Downstream applications checking the original URL or expecting strict error handling will bypass input validation filters. When the processed string is forwarded to native Node.js HTTP clients, the connection resolves to local loopback interfaces or private networks, facilitating Server-Side Request Forgery (SSRF).
The root cause of this vulnerability lies in the sequential scanner logic implemented within the internal getIPV6 helper function located in lib/utils.js. In vulnerable versions of fast-uri, the parser steps through characters sequentially inside bracketed literals without maintaining a strict state machine or validating against RFC 3986 IPv6 standards.
When parsing a host like [::not-valid], the scanner begins processing characters. Upon reaching the non-hexadecimal character n, the parser's logic halts or exits processing of the current segment without raising an error. The current buffer of successfully parsed characters (the :: prefix) is then used to construct the finalized host address.
Consequently, the host resolves to [::] (the unspecified address), while the malformed suffix :not-valid is silently discarded. Other malformed patterns similarly collapse into valid private or loopback ranges, such as [fc00::not-hex] collapsing into [fc00::]. Because the parser returns the output object with the error property set to false, downstream verification blocks treat the host as structurally valid and safe.
To understand the technical mechanics of the failure, analyze the structure of the getIPV6 function in the vulnerable version of lib/utils.js. The parser maintains state in arrays but allows loop exits that truncate input rather than forcing validation failure.
// Vulnerable sequential loop inside getIPV6 (lib/utils.js)
for (let i = 0; i < input.length; i++) {
const cursor = input[i]
if (cursor === '[' || cursor === ']') { continue }
if (cursor === ':') {
// ...
if (!consume()) { break } // Silent break on parsing error
// ...
}
}
// Truncation occurs silently when exiting loop with partial buffer
if (buffer.length) {
if (isZone) {
output.zone = buffer.join('')
} else {
address.push(stringArrayToHexStripped(buffer))
}
}
output.address = address.join('')
return outputThe patched version replaces this highly permissive sequential traversal with strict regular expression assertions matching RFC 3986 standards. Rather than stripping characters, the implementation explicitly returns undefined or throws an error when structural requirements are violated.
// Patched validation utilizing explicit RFC regular expressions
function normalizeIPv6Address (input) {
const compression = input.indexOf('::')
if (compression !== -1 && input.indexOf('::', compression + 1) !== -1) return undefined
const left = compression === -1 ? input.split(':') : input.slice(0, compression).split(':')
const right = compression === -1 ? [] : input.slice(compression + 2).split(':')
// ...
for (let i = 0; i < parts.length; i++) {
const part = parts[i]
if (part === '') return undefined
if (!isHextet(part)) return undefined // Rejects non-hexadecimal inputs immediately
}
// ...
}Additionally, the patch alters index.js to ensure the core parser (parseWithStatus) processes the validation failure from normalizeIPv6(). If the bracketed IP literal generates an error during normalisation, malformedIPLiteral is evaluated as true, setting the parsed error state to URI host is malformed. and blocking downstream normalization.
An attacker can exploit this vulnerability to achieve Server-Side Request Forgery (SSRF) or bypass network access policies designed to restrict internal service routing. This attack scenario requires the target application to accept user-controlled URLs, parse them with fast-uri for security checks, and execute outbound HTTP requests using Node.js clients like undici or axios.
In a standard SSRF scenario, an attacker issues a POST request to an external endpoint with the payload http://[::not-valid]:8080/admin. The security middleware uses fast-uri to parse the host. Because [::not-valid] is not explicitly found in standard local domain blocklists (such as localhost, 127.0.0.1, or [::1]), the request is permitted by the filter.
Step 1: Attacker sends POST /fetch?url=http://[::not-valid]:8080/admin
Step 2: App validates URL -> fastURI.parse('http://[::not-valid]:8080/admin') -> parses host
Step 3: App normalizes URL -> fastURI.normalize() -> outputs 'http://[::]:8080/admin'
Step 4: App connects -> fetch('http://[::]:8080/admin') -> routes to localhost admin portal
During normalization, fast-uri reconstructs the host as [::] because the parser discarded the invalid :not-valid suffix. Node.js's underlying network stack resolves the unspecified IPv6 address [::] directly to the local host interface (127.0.0.1 or ::1). This mechanism routes the outbound HTTP request internally, exposing endpoints on port 8080 to the attacker without authorization.
The impact of CVE-2026-75975 is classified as High (CVSS v3.1 Score: 7.5). The vulnerability undermines the integrity of network perimeter definitions and routing restrictions. The attack complexity is low, as it does not require prior authentication or user interaction to exploit successfully.
Successful exploitation allows complete bypass of address-validation policies. Attackers gain access to arbitrary HTTP endpoints on the internal network segment. In cloud environments, this primitive can be leveraged to access sensitive metadata services (e.g., IMDSv1 at 169.254.169.254 or local IPv6 link-local addresses) to harvest API keys, database credentials, and session tokens.
Additionally, because the parser does not set an error state, security tools built on fast-uri cannot log or identify that a parser differential attack occurred. The silent rewriting of destination hosts prevents audit logging systems from accurately capturing the true target of outbound connections, creating a significant blind spot for incident response teams.
The primary remediation path is upgrading the fast-uri package to a patched release. Ensure that your application and transitive dependencies are upgraded. Depending on your version branch, apply the corresponding update:
Verify that the lockfiles (package-lock.json, yarn.lock, or pnpm-lock.yaml) reflect the updated version. If direct modification is restricted, utilize npm overrides or yarn resolutions to force transitive dependencies to resolve to the secure versions.
In environments where an immediate package upgrade is not feasible, implement a temporary input validation layer. Before passing user-supplied input to fast-uri, validate that any host containing bracketed literals strictly adheres to IPv6 structure. Reject URLs that match the regular expression /^https?:\/\/\[.*?[^a-fA-F0-9:].*?\]/ to prevent silent truncation.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
fast-uri Fastify / OpenJS Foundation | >= 2.3.1, < 2.4.5 | 2.4.5 |
fast-uri Fastify / OpenJS Foundation | >= 3.0.0, < 3.1.6 | 3.1.6 |
fast-uri Fastify / OpenJS Foundation | >= 4.0.0, < 4.1.3 | 4.1.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-20, CWE-918 |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 Score | 7.5 (High) |
| Exploit Maturity | Proof of Concept (PoC) |
| CISA KEV Status | Not Listed |
| Impact | Integrity (High), Server-Side Request Forgery (SSRF) |
The product does not validate or incorrectly validates input that can affect the control flow or data flow of a program.
A double-decoding vulnerability in the fast-uri package allows unauthenticated remote attackers to bypass host-policy validation and conduct Server-Side Request Forgery (SSRF) attacks by submitting nested percent-encoded URI strings.
A host confusion vulnerability exists in the fast-uri Node.js library when parsing scheme-relative URI references. Due to inconsistent domain name canonicalization, applications validating resolved hosts can be bypassed by downstream WHATWG-compliant parsers, facilitating Server-Side Request Forgery (SSRF).
Sulu CMS, an open-source PHP content management system based on the Symfony framework, is affected by an Insecure Direct Object Reference (IDOR) vulnerability within its media relocation API. Authenticated users with restricted edit permissions can relocate media out of secure, unauthorized collections into folders they control, bypassing access controls entirely. This security issue is tracked under CVE-2026-82395 and GHSA-h6cx-gjxx-v25c.
An incomplete sanitization fix for CVE-2026-35536 in Tornado allowed cookie attribute injection. The framework's validation loop checked lowercase keyword arguments but neglected legacy case-insensitive parameters passed through arbitrary keyword arguments, which Python's underlying library parses case-insensitively.
GHSA-8423-8FGW-73VQ is a pre-authentication denial of service vulnerability in the Tornado web server's handling of multipart/form-data. The flaw allows an unauthenticated remote attacker to cause memory exhaustion and CPU starvation by transmitting a crafted HTTP request containing a high density of boundary delimiters. Because Tornado splits the entire request body in memory prior to enforcing the max_parts validation threshold, the Python interpreter attempts to materialize a massive list of byte segments. This triggers an immediate memory exhaustion (OOM) crash or server-wide CPU starvation before the payload can be validated and rejected.
The league/commonmark library is subject to multiple denial of service vulnerabilities. These stem from three independent algorithmic complexity weaknesses in Markdown parsing: regular expression backtracking, reference link normalization, and delimiter processing. Remote, unauthenticated attackers can exploit these flaws by submitting crafted Markdown input to exhaust CPU execution resources, leading to application-wide thread exhaustion.