HexBrain

Node.js · Report #395845

url.parse() hostname spoofing via javascript: URIs

Validstatus
mediumseverity
11upvotes
15 Jan 2020disclosed

How it was found

Summary:

Using url.parse() in security sensitive checks is dangerous as an arbitrary hostname can be spoofed via javascript: URIs.

Description:

The original url.parse() API is dangerous as it allows to spoof an arbitrary hostname via a javascript: URI:

$ node -e 'console.log(require("url").parse("javAscript:alert(1);a=\[email protected]\x27"))'
Url {
  protocol: 'javascript:',
  slashes: null,
  auth: 'alert(1);a=\'',
  host: 'white-listed.com',
  port: null,
  hostname: 'white-listed.com',
  hash: null,
  search: null,
  query: null,
  pathname: '\'',
  path: '\'',
  href: 'javascript:alert(1)%3Ba%3D\'@white-listed.com\'' }

Steps To Reproduce:

  1. node -e 'console.log(require("url").parse("javAscript:alert(1);a=\[email protected]\x27"))'

After a quick look, I believe the issue stems from case-sensitive checks on lines 268 and 275

Additional notes:

I didn't set the severity as I have no idea how widely the "Legacy API" is still used and the actual impact is hugely context-based. For the sake of completeness, I found this issue when testing a real world app.

This also affects this npm package. The WHATWG API handles this particular case well.

In might be a good idea to mention in the documentation that URL parsing shouldn't be relied on in security relevant context. Exact string matching or similarly simple concepts should be always preferred.

Impact

This can be dangerous if used in security relevant access controls as follows:

let parsedUrl = UrlHelper.parse(url); // url = javAscript:alert(1);a='@localhost/'
if (parsedUrl.hostname === 'localhost') { // parsedUrl.hostname = localhost
  return true; // and do something like window.location = url 
}

Although being a bad practice, developers will write this code and will introduce bypassable access controls. Given that the bypass works only with javascript: URIs this will likely lead to XSS in most cases.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original