VYPR
Moderate severityNVD Advisory· Published Dec 30, 2020· Updated Aug 4, 2024

Hostname spoofing in URI.js

CVE-2020-26291

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.

PackageAffected versionsPatched versions
urijsnpm
< 1.19.41.19.4

Affected products

2
  • ghsa-coords
    Range: < 1.19.4
  • medialize/URI.jsv5
    Range: < 1.19.4

Patches

1
b02bf037c99a

fix(parse): treat backslash as forwardslash in authority (#403)

https://github.com/medialize/URI.jsAlesandro OrtizDec 23, 2020via ghsa
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

News mentions

0

No linked articles in our index yet.