Impact
fast-uri decodes a hostname's percent escapes twice in a single normalize() or resolve() call: once during parsing and again during authority recomposition. A nested percent-encoded host therefore survives the first decode and is turned into a live destination by the second, so normalize('http://%256c%256f%2563%2561%256c%2568%256f%2573%2574/') returns http://localhost/. Applications that normalize or resolve an untrusted URI before an SSRF check, redirect validation, or host allowlist can be steered to a different destination, including internal addresses such as loopback or a cloud metadata endpoint, than the encoded input appeared to contain. This is an incomplete-fix variant of CVE-2026-6322, whose encoded-authority-delimiter fix introduced the second decode.
Patches
Fixed in fast-uri 2.4.5, 3.1.6, and 4.1.3.
Workarounds
Reject untrusted URIs whose host component contains an encoded percent sign (%25) before passing them to normalize() or resolve().
Impact
fast-uri's serialize(), normalize(), and resolve(), when called with the non-default option reference: 'suffix' on a reference that has no authority, emit a relative reference whose first path segment contains a bare colon without escaping it. RFC 3986 section 3.3 requires the first segment of a path-noscheme reference not to contain a colon, precisely because a bare colon makes the string reparse as an absolute URI with a scheme. fast-uri's default serialization escapes that colon, but the suffix path does not.
For example, normalize('javascript:alert(1)', { reference: 'suffix' }) returns javascript:alert(1), which reparses as a live javascript: scheme; data: and vbscript: behave the same.
Applications that serialize or normalize a relative reference with reference: 'suffix' and then treat the result as a URI can turn inert input into a live javascript:, data:, or vbscript: URL (a cross-site scripting vector), and equal() can conflate a scheme-bearing reference with a relative one. Exposure is limited to applications that use the non-default reference: 'suffix' option.
Patches
Upgrade to fast-uri 2.4.8, 3.1.9, or 4.2.3.
Workarounds
Do not use the reference: 'suffix' option on untrusted input. If suffix output is required, percent-encode a colon in the first path segment of the result before treating it as a URI.
Impact
fast-uri folds the host to lowercase before it percent-decodes the host, so a percent-encoded uppercase unreserved octet such as %41 decodes to a literal A that is never folded. For a scheme-relative reference (//host) there is no scheme, so the host canonicalization that repairs this on a scheme-bearing URL does not run. As a result parse, normalize, and equal disagree on the same host: parse("//%41.com").host returns "A.com" while parse("//a.com").host and parse("//A.com").host return "a.com", and equal("//%41.com", "//a.com") is false even though equal("//A.com", "//a.com") is true. An application that makes a case-sensitive host decision on fast-uri output for a scheme-relative reference, for example a host allowlist or denylist that compares parse(url).host or uses fast-uri.equal, can be steered past the check with a percent-encoded uppercase octet. Because a hostname is case-insensitive in DNS and HTTP routing, the evading spelling reaches the same host the check meant to gate, so the effect is check evasion rather than reaching a different registrable host.
Patches
Upgrade to fast-uri 4.1.5, 3.1.8, or 2.4.7.
Workarounds
Compare hosts case-insensitively (lowercase the parsed host before any allowlist or denylist decision), or avoid making case-sensitive host decisions on scheme-relative input until upgrading.
Impact
fast-uri canonicalizes a host to its ASCII form only when the input carries an explicit scheme. When resolve() resolves a scheme-relative reference (//host/) against a scheme-bearing base, it still emits the host verbatim even though the effective scheme is known, so re-parsing the resolved URI yields a different host than the one resolve() returned. An application that resolves an untrusted reference with fast-uri and then checks or routes on the resulting host can make a policy decision on one host and reach another. This is an incomplete-fix variant of CVE-2026-13676, whose IDN canonicalization was applied only to the scheme-bearing form.
Patches
Upgrade to fast-uri 2.4.5, 3.1.6, or 4.1.3. resolve() now canonicalizes the host once the effective scheme is known, and fails closed if a raw non-ASCII host cannot be converted.
Workarounds
Resolve scheme-relative references against a base that carries a scheme before performing any host-policy or origin check.
Impact
fast-uri does not validate the complete RFC 3986 grammar for bracketed IPv6 literals, so a malformed literal with invalid trailing text is silently truncated to a different valid IPv6 address with no error reported. For example, normalize('http://[::not-valid]/private') returns http://[::]/private, and [fc00::not-hex] and [fe80::not-hex] collapse to [fc00::] and [fe80::]. An application that normalizes an untrusted URL before an outbound request, redirect, or host-policy check can be routed to a local or private address such as loopback (::1), unique-local, or link-local. Because parse().error is unset for these inputs, checking it does not protect the consumer.
Patches
Upgrade to fast-uri 2.4.5, 3.1.6, or 4.1.3. Malformed IPv6 literals are now rejected with a host error instead of being normalized to a valid address.
Workarounds
Reject untrusted URLs whose host is a bracketed IPv6 literal before passing them to fast-uri, or route outbound requests against an explicit allowlist of addresses rather than trusting the normalized host.
Impact
fast-uri accepts a host that contains an unbalanced or misplaced authority bracket ([ or ]) without reporting an error. A host that starts with [ but does not end with ], such as [@127.0.0.1, is neither validated as an IP literal nor canonicalized as a domain name, so parse() returns it as the host with error undefined, while Node's URL (and http.get, axios, got, and other clients built on it) resolve the same string to 127.0.0.1. An application that reads parse().host to make a host decision (an SSRF denylist, a redirect allowlist, or proxy routing) and then passes the original URL to an HTTP client evaluates its policy against a string that is not the host the request reaches. The same host is carried through normalize(), equal(), and resolve().
Patches
This vulnerability has been patched in fast-uri 4.1.4, 3.1.7, and 2.4.6. parse() now reports URI host is malformed. for any host that contains a bracket but is not a valid [IPv6] literal. All users should upgrade.
Workarounds
If upgrading is not immediately possible, reject any URL whose host contains a [ or ] that is not a well-formed IPv6 literal before making a host decision. Clients that fail closed on credential-bearing URLs, such as Node's global fetch(), are not affected by the reported vector.
fast-uri is a URI parser for Node.js. It canonicalizes a host to its ASCII form only when the input carries an explicit scheme, so a scheme-relative reference such as a host preceded by two slashes is returned with its host verbatim and no error set. As a result fast-uri's own entry points disagree with each other: parse, resolve, normalize, and equal can yield different hosts for the same input depending only on whether a scheme is written out, and equal can return opposite verdicts for the same pair of hosts. An application that extracts a host with fast-uri to check it against a policy list and then resolves the same reference can make its decision on one host while the destination is another, enabling host confusion and policy bypass. The affected versions are 2.4.2 up to but not including 2.4.5, 3.1.3 up to but not including 3.1.6, and 4.0.1 up to but not including 4.1.3. The issue is fixed in 2.4.5, 3.1.6, and 4.1.3, which canonicalize the host consistently across the resolve path. Users should upgrade to a patched version.
fast-uri is a URI parser for Node.js. Its custom parser for bracketed IPv6 literals does not validate the complete IPv6 grammar, so invalid trailing text in an authority can be silently discarded and a malformed attacker-controlled host is turned into a different valid IPv6 destination. For example, a bracketed literal with invalid trailing characters is normalized to the unspecified address, which a Node HTTP client then connects to a local service over loopback, and other malformed literals collapse to private-range addresses. No error is set on the parsed result, so an application checking the error field cannot detect the rewrite. An application that normalizes untrusted URLs before outbound requests, redirects, proxy routing, or address-policy enforcement can be redirected to a local or private IPv6 target, giving a server-side request forgery and address-policy bypass primitive. The affected versions are 2.3.1 up to but not including 2.4.5, 3.0.0 up to but not including 3.1.6, and 4.0.0 up to but not including 4.1.3. The issue is fixed in 2.4.5, 3.1.6, and 4.1.3, which validate bracketed IP literals against the full grammar and mark malformed literals as authority errors. Users should upgrade to a patched version.
fast-uri accepts a host that contains an unbalanced or misplaced authority bracket without reporting an error. A host that starts with an opening bracket but does not end with a closing bracket is neither validated as an IP literal nor canonicalized as a domain name, so parse() returns it as the host with error undefined, while Node's URL and the HTTP clients built on it resolve the same string to a different host. An application that reads the parsed host to make a host decision, such as an SSRF denylist, a redirect allowlist, or proxy routing, and then passes the original URL to an HTTP client evaluates its policy against a string that is not the host the request reaches. The same host is carried through normalize, equal, and resolve. This affects fast-uri versions 2.4.5, 3.1.6, and 4.1.3, and is fixed in 2.4.6, 3.1.7, and 4.1.4, where parse() reports a malformed host for any host that contains a bracket but is not a valid IPv6 literal.
fast-uri before 4.1.2, 3.1.5, and 2.4.4 requires a literal double forward slash to recognize a URI authority, so a reference that uses a backslash based introducer in place of it (backslash backslash, forward slash backslash, or backslash forward slash) is parsed with no authority and folds into the path. Node's native WHATWG URL parser instead treats a backslash as interchangeable with a forward slash for special schemes, so the two parsers extract different hosts from the same input. Applications that use fast-uri to enforce host based policy such as allowlists, SSRF filtering, or redirect validation before passing the same URL into Node's URL or fetch consumers can be steered to an unintended host. Upgrade to fast-uri 4.1.2, 3.1.5, or 2.4.4.
fast-uri is a URI parser for Node.js. During parsing it runs a legacy decoding pass over the scheme component and never re-escapes the result, and serialization writes the scheme back out verbatim, unlike the host component which is re-escaped. As a result an input whose scheme carries percent-encoded slashes parses as a scheme with no authority, so the parsed host and error are both undefined, yet resolving or normalizing that same input emits a network-path reference whose authority is attacker-chosen and re-parses to that host. An application that allowlists on the parsed host, or treats a reference with no authority as safe to resolve against its base, gets the opposite of what it checked, giving an off-site redirect, server-side request forgery, or address-policy bypass. The legacy decoder also expands non-standard escape forms, widening the issue past upstream filters, and control characters in the scheme can reach the output as raw carriage return and line feed. The affected versions are 2.3.1 up to but not including 2.4.5, 3.0.0 up to but not including 3.1.6, and 4.0.0 up to but not including 4.1.3. The issue is fixed in 2.4.5, 3.1.6, and 4.1.3, which reject a scheme that is not valid after decoding. Users should upgrade to a patched version.
fast-uri serializes the port component of a URI without validating it. When recomposing the authority, the userinfo and host components are escaped but the port is concatenated verbatim, so a port value that is not a sequence of digits can inject authority delimiters, demoting the intended host to userinfo and pointing the authority at an attacker-controlled host. Both fast-uri and Node's URL read the result back as the attacker's host with no error, so re-validating the built URI does not catch it. This affects applications that build URIs from parts and assign untrusted data to the port component through the serialize, normalize, or equal functions in their object forms. The issue affects fast-uri versions before 2.4.6, from 3.0.0 before 3.1.7, and from 4.0.0 before 4.1.4. It is fixed in 2.4.6, 3.1.7, and 4.1.4, where recomposeAuthority rejects any port that is not a digit sequence per RFC 3986.
fast-uri is a URI parser for Node.js. It decodes percent escapes in a hostname during parsing and then decodes the parsed hostname a second time during authority recomposition, so a single call to normalize or resolve can turn nested percent-encoded input into a different network destination such as a loopback hostname or address. For example, a doubly encoded host that spells out a loopback name decodes to that live host in one operation, which contradicts RFC 3986 section 2.4 that an implementation must not decode the same string more than once. An application that normalizes or resolves an untrusted HTTP-family URI before outbound routing, redirect validation, or a host-policy check can receive a destination different from the one the original encoded host represented, giving a server-side request forgery and host-policy bypass primitive. This is an incomplete-fix variant of CVE-2026-6322. The affected versions are 2.4.1 up to but not including 2.4.5, 3.1.2 up to but not including 3.1.6, and 4.0.0 up to but not including 4.1.3. The issue is fixed in 2.4.5, 3.1.6, and 4.1.3, which normalize percent escapes once and preserve encoded percent signs. Users should upgrade to a patched version.
Impact
fast-uri v3.1.1 and earlier decodes percent-encoded authority delimiters (%40 as @, %3A as :) inside the host component and serializes them back as raw characters. This changes the URI structure, turning a hostname into userinfo plus a different host.
For example, http://trusted.com%40evil.com/ normalizes to http://trusted.com@evil.com/, which reparses as host evil.com with userinfo trusted.com.
Applications that normalize untrusted URLs before host allowlist checks, redirect validation, or outbound request routing can be steered to a different authority than the original URL appeared to contain.
Patches
Upgrade to fast-uri >= 3.1.2.
Workarounds
None. Upgrade to the patched version.
Impact
fast-uri v4.1.0 and earlier do not treat a literal backslash (U+005C) as an authority delimiter. Node's native WHATWG URL (used by fetch(), undici, and Node's http/https clients) normalizes \ to / for special schemes (http, https, ws, wss, ftp, file), so the two parsers extract different hosts from the same input string.
For example, http://evil.com\@allowed.com is treated by fast-uri as host allowed.com with userinfo evil.com\, while Node's WHATWG URL parser and fetch() see host evil.com with path /@allowed.com.
Applications that use fast-uri to enforce host-based policy (allowlists, denylists, loopback/SSRF filtering, redirect validation, outbound proxy routing) before passing the same URL into Node's URL or fetch() consumers see a policy/use desync and can be steered to an unintended destination, including cloud metadata endpoints, loopback, or internal hosts.
Patches
Upgrade to fast-uri v4.1.1, v3.1.4, or v2.4.3.
Workarounds
None. Upgrade to the patched version.
Impact: fast-uri versions from 2.3.1 through 4.1.0 (including the 3.x line up to 3.1.3 and the 2.x line up to 2.4.2) do not treat a literal backslash character (U+005C) as an authority delimiter. Node's native WHATWG URL parser, used by fetch, undici, and Node's http and https clients, normalizes the backslash to a forward slash for special schemes such as http, https, ws, wss, ftp, and file. As a result, the two parsers extract different hosts from the same input string. Applications that use fast-uri to enforce host-based policy such as allowlists, denylists, loopback or SSRF filtering, redirect validation, or outbound proxy routing before passing the same URL into Node's URL or fetch consumers can be steered to an unintended destination, including cloud metadata endpoints, loopback, or internal hosts.
Patches: upgrade to fast-uri 4.1.1, 3.1.4, or 2.4.3.
Workarounds: none.
Impact
fast-uri's mailto scheme parser compares each query field name to the reserved names (to, subject, body) while the name is still percent-encoded, and only percent-decodes it when storing it as a generic header. On serialize, the decoded name is re-emitted, so a field name such as %74o (percent-encoded to) is not recognized as a recipient at parse time (parse().to shows only the legitimate recipient) but materializes as a literal to= field after serialize(), and reparsing then treats it as a recipient. The same technique smuggles subject and body through %73ubject and %62ody.
An application that parses an untrusted mailto URI, makes a display, allowlist, or logging decision on parse().to, then re-serializes the result and passes the serialized string to a mail client or an outbound send path can gain an attacker-chosen recipient, subject, or body that was not visible when the recipient list was checked. A scanner inspecting the raw input for an extra to= sees nothing, because the injected field appears only after fast-uri serializes.
Patches
Upgrade to fast-uri 4.1.5.
Workarounds
Percent-decode and compare mailto field names case-insensitively before trusting parse().to, or re-check the recipient list on the serialized output rather than only on the initial parse, until upgrading.
Impact
fast-uri versions >= 2.4.2, <= 2.4.7, >= 3.1.3, <= 3.1.8, and >= 4.0.1, <= 4.2.2 can silently rewrite the host of an HTTP-family URL (http, https, ws, wss, or any scheme with domainHost: true). For those schemes canonicalizeHost() passes the parsed host to the WHATWG URL parser and adopts its .hostname without checking that the parser read the whole input as a host. RFC 3986 permits @ inside the host group and the WHATWG parser strips TAB, LF, and CR, so the authority fast-uri reports is rewritten by that second parser with no error set: data before an @ is dropped and whitespace is removed.
For example, fast-uri parses http://a@b@evil.example/ to host evil.example (dropping the b segment), and a host containing a raw TAB, CR, or LF has those characters stripped. equal() then treats a whitespace-smuggled host as the same as the clean one, and resolve() rewrites the authority the same way.
Applications that use fast-uri to enforce host-based policy (denylists, loopback filtering, redirect validation, outbound proxy routing) on one representation, such as the raw input, see a policy/use desync: the canonical host fast-uri returns differs from what was checked, and traffic can be steered to an unintended destination.
Patches
Upgrade to fast-uri 2.4.8, 3.1.9, or 4.2.3.
Workarounds
Reject URIs whose authority contains more than one @, or contains TAB, CR, or LF, before calling fast-uri. Alternatively, treat any non-empty parse(x).error as fatal, and compare hosts only from the same parse() result.
Impact
fast-uri's normalize() and serialize() apply RFC 3986 dot-segment removal (removedotsegments) to the path of a relative-path reference. RFC 3986 section 5.2.4 defines that algorithm only for the merged target path during resolution, not for the reference itself, so applied to the reference it drops leading .. segments and can turn a document-relative reference into a root-relative one.
For example, normalize('a/../b') returns /b and normalize('../x') returns x, so resolve(base, normalize(ref)) points at a different resource than resolve(base, ref), and equal() treats distinct references as the same.
Applications that normalize attacker-supplied or user-supplied relative references and then resolve them, or use them as cache, deduplication, or authorization keys, can have a reference escape its intended directory and point at a different resource.
Patches
Upgrade to fast-uri 2.4.8, 3.1.9, or 4.2.3.
Workarounds
Do not normalize a relative reference before resolving it. Resolve it against the absolute base first, then normalize the absolute result.
Impact
fast-uri percent-decodes the scheme component with the legacy global unescape() before validating it, so an input whose decoded scheme is a valid but dangerous token is emitted as a live scheme. RFC 3986 section 3.1 does not allow percent-encoding in a scheme, so no RFC or WHATWG parser treats such input as having that scheme, but fast-uri does.
For example, normalize('%6Aavascript:alert(1)') returns javascript:alert(1), resolve('https://a.example/', '%6Aavascript:alert(1)') returns javascript:alert(1), and parse('%6Aavascript:alert(1)').scheme returns javascript. The %uXXXX form (%u006Aavascript:) produces the same result, and equal('%68ttp://a/', 'http://a/') returns true.
An application that screens dangerous schemes on the raw input and then stores or renders normalize(input) or resolve(base, input) turns an inert string into an executable javascript:, data:, or vbscript: URL, a stored or reflected cross-site scripting vector in the consuming application. equal() also treats an encoded and a plain scheme as the same, which can bypass equality-based allowlists.
Patches
Upgrade to fast-uri 2.4.8, 3.1.9, or 4.2.3.
Workarounds
Reject input whose scheme part (before the first :, and before any /, ?, or #) contains %. Alternatively, check parse(x).scheme against an allowlist after normalization and use that same parsed result rather than the raw string.