Skip to content

Commit 3ecd256

Browse files
committedApr 11, 2019
[security] Trim left to prevent unsantitized input from generating false positives
1 parent 6667379 commit 3ecd256

File tree

3 files changed

+43
-1
lines changed

3 files changed

+43
-1
lines changed
 

‎SECURITY.md

+10
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ acknowledge your responsible disclosure, if you wish.
3333

3434
## History
3535

36+
> The `extractProtocol` method does not return the correct protocol when
37+
> provided with unsanitized content which could lead to false positives.
38+
39+
- **Reporter credits**
40+
- Reported through our security email & Twitter interaction.
41+
- Twitter: [@ronperris](https://twitter.com/ronperris)
42+
- Fixed in: 1.4.5
43+
44+
---
45+
3646
> url-parse returns wrong hostname which leads to multiple vulnerabilities such
3747
> as SSRF, Open Redirect, Bypass Authentication Protocol.
3848

‎index.js

+17-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,20 @@
22

33
var required = require('requires-port')
44
, qs = require('querystringify')
5+
, slashes = /^[A-Za-z][A-Za-z0-9+-.]*:\/\//
56
, protocolre = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\S\s]*)/i
6-
, slashes = /^[A-Za-z][A-Za-z0-9+-.]*:\/\//;
7+
, 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]'
8+
, left = new RegExp('^'+ whitespace +'+');
9+
10+
/**
11+
* Trim a given string.
12+
*
13+
* @param {String} str String to trim.
14+
* @public
15+
*/
16+
function trimLeft(str) {
17+
return (str || '').replace(left, '');
18+
}
719

820
/**
921
* These are the parse rules for the URL parser, it informs the parser
@@ -102,6 +114,7 @@ function lolcation(loc) {
102114
* @private
103115
*/
104116
function extractProtocol(address) {
117+
address = trimLeft(address);
105118
var match = protocolre.exec(address);
106119

107120
return {
@@ -162,6 +175,8 @@ function resolve(relative, base) {
162175
* @private
163176
*/
164177
function Url(address, location, parser) {
178+
address = trimLeft(address);
179+
165180
if (!(this instanceof Url)) {
166181
return new Url(address, location, parser);
167182
}
@@ -429,6 +444,7 @@ Url.prototype = { set: set, toString: toString };
429444
//
430445
Url.extractProtocol = extractProtocol;
431446
Url.location = lolcation;
447+
Url.trimLeft = trimLeft;
432448
Url.qs = qs;
433449

434450
module.exports = Url;

‎test/test.js

+16
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ describe('url-parse', function () {
4444

4545
describe('extractProtocol', function () {
4646
it('extracts the protocol data', function () {
47+
assume(parse.extractProtocol('http://example.com')).eql({
48+
slashes: true,
49+
protocol: 'http:',
50+
rest: 'example.com'
51+
});
52+
});
53+
54+
it('extracts the protocol data for nothing', function () {
4755
assume(parse.extractProtocol('')).eql({
4856
slashes: false,
4957
protocol: '',
@@ -60,6 +68,14 @@ describe('url-parse', function () {
6068
rest: input
6169
});
6270
});
71+
72+
it('trimsLeft', function () {
73+
assume(parse.extractProtocol(' javascript://foo')).eql({
74+
slashes: true,
75+
protocol: 'javascript:',
76+
rest: 'foo'
77+
});
78+
});
6379
});
6480

6581
it('parses the query string into an object', function () {

0 commit comments

Comments
 (0)
Please sign in to comment.