Hostname spoofing in URI.js
Description
URI.js is a javascript URL mutation library (npm package urijs). In URI.js before version 1.19.4, the hostname can be spoofed by using a backslash (\) character followed by an at (@) character. If the hostname is used in security decisions, the decision may be incorrect. Depending on library usage and attacker intent, impacts may include allow/block list bypasses, SSRF attacks, open redirects, or other undesired behavior. For example the URL https://expected-example.com\@observed-example.com will incorrectly return observed-example.com if using an affected version. Patched versions correctly return expected-example.com. Patched versions match the behavior of other parsers which implement the WHATWG URL specification, including web browsers and Node's built-in URL class. Version 1.19.4 is patched against all known payload variants. Version 1.19.3 has a partial patch but is still vulnerable to a payload variant.]
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
URI.js before 1.19.4 misparses backslash+@ in URLs, allowing hostname spoofing that can bypass security checks and enable SSRF or open redirects.
Vulnerability
Description URI.js (npm package urijs) is a JavaScript URL mutation library. In versions prior to 1.19.4, the library incorrectly parses URLs containing a backslash (\) followed by an at sign (@). For example, the URL https://expected-example.com\@observed-example.com is parsed as having hostname observed-example.com instead of expected-example.com [1]. This behavior deviates from the WHATWG URL specification followed by modern browsers and Node.js [1].
Exploitation
An attacker can craft a URL that appears to point to a trusted host but actually resolves to a different host when processed by URI.js. The attack requires no special privileges; any application using URI.js to parse or validate URLs for security decisions (e.g., allow/block lists, redirect targets) is vulnerable [1]. The backslash is treated as a path separator, and the @ is interpreted as userinfo delimiter, leading to hostname confusion [3].
Impact
Successful exploitation can lead to allow/block list bypasses, server-side request forgery (SSRF), open redirects, or other attacks depending on how the parsed hostname is used [1]. For instance, an application that checks a URL's hostname against a whitelist might be tricked into allowing a malicious destination.
Mitigation
The vulnerability is fixed in URI.js version 1.19.4, which correctly treats backslashes as forward slashes in the authority component, matching browser behavior [3][4]. Version 1.19.3 provided a partial fix but remained vulnerable to some payload variants [1]. Users should upgrade to 1.19.4 or later.
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
urijsnpm | < 1.19.4 | 1.19.4 |
Affected products
2- medialize/URI.jsv5Range: < 1.19.4
Patches
1b02bf037c99afix(parse): treat backslash as forwardslash in authority (#403)
2 files changed · +55 −3
src/URI.js+6 −3 modified@@ -612,19 +612,22 @@ }; URI.parseUserinfo = function(string, parts) { // extract username:password + var _string = string var firstBackSlash = string.indexOf('\\'); + if (firstBackSlash !== -1) { + string = string.replace(/\\/g, '/') + } var firstSlash = string.indexOf('/'); - var slash = firstBackSlash === -1 ? firstSlash : (firstSlash !== -1 ? Math.min(firstBackSlash, firstSlash): firstSlash) var pos = string.lastIndexOf('@', firstSlash > -1 ? firstSlash : string.length - 1); var t; // authority@ must come before /path or \path - if (pos > -1 && (slash === -1 || pos < slash)) { + if (pos > -1 && (firstSlash === -1 || pos < firstSlash)) { t = string.substring(0, pos).split(':'); parts.username = t[0] ? URI.decode(t[0]) : null; t.shift(); parts.password = t[0] ? URI.decode(t.join(':')) : null; - string = string.substring(pos + 1); + string = _string.substring(pos + 1); } else { parts.username = null; parts.password = null;
test/urls.js+49 −0 modified@@ -2033,6 +2033,55 @@ var urls = [{ idn: false, punycode: false } + }, { + name: 'backslashes authority, no ending slash', + url: 'https://attacker.com\\@example.com', + _url: 'https://attacker.com/@example.com', + parts: { + protocol: 'https', + username: null, + password: null, + hostname: 'attacker.com', + port: null, + path: '/@example.com', + query: null, + fragment: null + }, + accessors: { + protocol: 'https', + username: '', + password: '', + port: '', + path: '/@example.com', + query: '', + fragment: '', + resource: '/@example.com', + authority: 'attacker.com', + origin: 'https://attacker.com', + userinfo: '', + subdomain: '', + domain: 'attacker.com', + tld: 'com', + directory: '/', + filename: '@example.com', + suffix: 'com', + hash: '', + search: '', + host: 'attacker.com', + hostname: 'attacker.com' + }, + is: { + urn: false, + url: true, + relative: false, + name: true, + sld: false, + ip: false, + ip4: false, + ip6: false, + idn: false, + punycode: false + } } ];
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
7- github.com/advisories/GHSA-3329-pjwv-fjpgghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2020-26291ghsaADVISORY
- github.com/medialize/URI.js/commit/b02bf037c99ac9316b77ff8bfd840e90becf1155ghsax_refsource_MISCWEB
- github.com/medialize/URI.js/releases/tag/v1.19.4ghsax_refsource_MISCWEB
- github.com/medialize/URI.js/security/advisories/GHSA-3329-pjwv-fjpgghsax_refsource_CONFIRMWEB
- www.npmjs.com/advisories/1595ghsaWEB
- www.npmjs.com/package/urijsghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.