This is a URL confusion vulnerability.
When parsing a URL without a scheme and with excessive slashes, like ///www.example.com
, URI.js will parse the hostname as null
and the path as /www.example.com
.
Such behaviour is different from that exhibited by browsers, which will parse ///www.example.com
as http://www.example.com
instead. For example, the following will cause a redirect to http://www.example.com
:
window.location.href = "///www.example.com";
This can lead to a variety of vulnerabilities including open redirects, where the target host is parsed and validated using URI.js.
const uri = require('urijs');
let payload = "///evil.com";
console.log(new uri(payload));
Output:
URI {
_string: '',
_parts: {
protocol: null,
username: null,
password: null,
hostname: null,
urn: null,
port: null,
path: '/evil.com',
query: null,
fragment: null,
preventInvalidHostname: false,
duplicateQueryParameters: false,
escapeQuerySpace: true
},
_deferred_build: true
}
Node’s WHATWG URL API and URL parsers of other languages would deem this as an invalid URL and throw an error.
Example of flawed validation and browser behaviour:
<html>
<body>
<script src="uri.js"></script>
<script>
let payload = "///www.example.com";
let parsed = new URI(payload);
if (parsed.hostname() === "www.example.com") {
alert("Hostname not allowed");
}
else {
window.location.href = payload;
}
</script>
</body>
</html>