diff --git a/SECURITY.md b/SECURITY.md index ea5a99c..a1c3d63 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -33,6 +33,16 @@ acknowledge your responsible disclosure, if you wish. ## History +> The `extractProtocol` method does not return the correct protocol when +> provided with unsanitized content which could lead to false positives. + +- **Reporter credits** + - Reported through our security email & Twitter interaction. + - Twitter: [@ronperris](https://twitter.com/ronperris) + - Fixed in: 1.4.5 + +--- + > url-parse returns wrong hostname which leads to multiple vulnerabilities such > as SSRF, Open Redirect, Bypass Authentication Protocol. diff --git a/index.js b/index.js index 621b56d..eaf5b25 100644 --- a/index.js +++ b/index.js @@ -2,8 +2,20 @@ var required = require('requires-port') , qs = require('querystringify') + , slashes = /^[A-Za-z][A-Za-z0-9+-.]*:\/\// , protocolre = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\S\s]*)/i - , slashes = /^[A-Za-z][A-Za-z0-9+-.]*:\/\//; + , whitespace = '[\\x09\\x0A\\x0B\\x0C\\x0D\\x20\\xA0\\u1680\\u180E\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200A\\u202F\\u205F\\u3000\\u2028\\u2029\\uFEFF]' + , left = new RegExp('^'+ whitespace +'+'); + +/** + * Trim a given string. + * + * @param {String} str String to trim. + * @public + */ +function trimLeft(str) { + return (str || '').replace(left, ''); +} /** * These are the parse rules for the URL parser, it informs the parser @@ -102,6 +114,7 @@ function lolcation(loc) { * @private */ function extractProtocol(address) { + address = trimLeft(address); var match = protocolre.exec(address); return { @@ -162,6 +175,8 @@ function resolve(relative, base) { * @private */ function Url(address, location, parser) { + address = trimLeft(address); + if (!(this instanceof Url)) { return new Url(address, location, parser); } @@ -429,6 +444,7 @@ Url.prototype = { set: set, toString: toString }; // Url.extractProtocol = extractProtocol; Url.location = lolcation; +Url.trimLeft = trimLeft; Url.qs = qs; module.exports = Url; diff --git a/test/test.js b/test/test.js index 3d64ae3..9218fe4 100644 --- a/test/test.js +++ b/test/test.js @@ -44,6 +44,14 @@ describe('url-parse', function () { describe('extractProtocol', function () { it('extracts the protocol data', function () { + assume(parse.extractProtocol('http://example.com')).eql({ + slashes: true, + protocol: 'http:', + rest: 'example.com' + }); + }); + + it('extracts the protocol data for nothing', function () { assume(parse.extractProtocol('')).eql({ slashes: false, protocol: '', @@ -60,6 +68,14 @@ describe('url-parse', function () { rest: input }); }); + + it('trimsLeft', function () { + assume(parse.extractProtocol(' javascript://foo')).eql({ + slashes: true, + protocol: 'javascript:', + rest: 'foo' + }); + }); }); it('parses the query string into an object', function () {