From 8e51b00911ba0f6e90949e2c4516b945c35021f7 Mon Sep 17 00:00:00 2001 From: Rodney Rehm Date: Sun, 21 Feb 2021 17:42:46 +0100 Subject: [PATCH] fix(parse): prevent overwriting __proto__ in parseQuery() issue was reported privately by @NewEraCracker --- src/URI.js | 10 ++++++++-- test/test.js | 8 ++++++++ test/urls.js | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/URI.js b/src/URI.js index de9954da..0a5e77ed 100644 --- a/src/URI.js +++ b/src/URI.js @@ -658,7 +658,10 @@ // no "=" is null according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#collect-url-parameters value = v.length ? URI.decodeQuery(v.join('='), escapeQuerySpace) : null; - if (hasOwn.call(items, name)) { + if (name === '__proto__') { + // ignore attempt at exploiting JavaScript internals + continue; + } else if (hasOwn.call(items, name)) { if (typeof items[name] === 'string' || items[name] === null) { items[name] = [items[name]]; } @@ -751,7 +754,10 @@ var t = ''; var unique, key, i, length; for (key in data) { - if (hasOwn.call(data, key)) { + if (key === '__proto__') { + // ignore attempt at exploiting JavaScript internals + continue; + } else if (hasOwn.call(data, key)) { if (isArray(data[key])) { unique = {}; for (i = 0, length = data[key].length; i < length; i++) { diff --git a/test/test.js b/test/test.js index 672b3f93..1953298a 100644 --- a/test/test.js +++ b/test/test.js @@ -418,6 +418,10 @@ equal(u.query(), 'foo&foo=bar', 'search: foo&foo=bar'); equal(JSON.stringify(u.query(true)), JSON.stringify({foo: [null, 'bar']}), 'parsed query: {foo:[null, "bar"]}'); + u.search('__proto__=hasOwnProperty&__proto__=eviltwin&uuid'); + equal(u.query(), '__proto__=hasOwnProperty&__proto__=eviltwin&uuid', 'search: __proto__=hasOwnProperty&__proto__=eviltwin&uuid'); + equal(JSON.stringify(u.query(true)), '{"uuid":null}', 'parsed query: {uuid: null}'); + // parsing empty query var t; t = u.query('?').query(true); @@ -931,6 +935,10 @@ u.setQuery('some value', 'must be encoded because of = and ? and #'); equal(u.query(), 'some+value=must+be+encoded+because+of+%3D+and+%3F+and+%23', 'encoding'); equal(u.query(true)['some value'], 'must be encoded because of = and ? and #', 'decoding'); + + u.query('?foo=bar'); + u.setQuery('__proto__', 'hasOwnProperty'); + equal(u.query(), 'foo=bar', 'set __proto__'); }); test('addQuery', function() { var u = URI('?foo=bar'); diff --git a/test/urls.js b/test/urls.js index c993038c..30547e6a 100644 --- a/test/urls.js +++ b/test/urls.js @@ -2131,6 +2131,54 @@ var urls = [{ idn: false, punycode: false } + }, { + name: '__proto__ in query', + url: 'http://www.example.org/?__proto__=hasOwnProperty&__proto__=eviltwin&uuid', + parts: { + protocol: 'http', + username: null, + password: null, + hostname: 'www.example.org', + port: null, + path: '/', + query: '__proto__=hasOwnProperty&__proto__=eviltwin&uuid', + fragment: null + }, + accessors: { + protocol: 'http', + username: '', + password: '', + port: '', + path: '/', + query: '__proto__=hasOwnProperty&__proto__=eviltwin&uuid', + fragment: '', + resource: '/?__proto__=hasOwnProperty&__proto__=eviltwin&uuid', + authority: 'www.example.org', + origin: 'http://www.example.org', + userinfo: '', + subdomain: 'www', + domain: 'example.org', + tld: 'org', + directory: '/', + filename: '', + suffix: '', + hash: '', + search: '?__proto__=hasOwnProperty&__proto__=eviltwin&uuid', + host: 'www.example.org', + hostname: 'www.example.org' + }, + is: { + urn: false, + url: true, + relative: false, + name: true, + sld: false, + ip: false, + ip4: false, + ip6: false, + idn: false, + punycode: false + } } ];