diff --git a/src/lib/isURL.js b/src/lib/isURL.js index 0fec384ba..3341dd0c9 100644 --- a/src/lib/isURL.js +++ b/src/lib/isURL.js @@ -95,7 +95,16 @@ export default function isURL(url, options) { if (!options.allow_protocol_relative_urls) { return false; } - split[0] = url.slice(2); + + // Block credentials in protocol-relative URLs, maar check alléén de authority + const pr = url.slice(2); + const firstSlash = pr.indexOf('/'); + const authority = firstSlash === -1 ? pr : pr.slice(0, firstSlash); + if (authority.indexOf('@') !== -1) { + return false; + } + + split[0] = pr; } url = split.join('://'); diff --git a/test/validators/isURL.bypass.test.js b/test/validators/isURL.bypass.test.js new file mode 100644 index 000000000..f09019f64 --- /dev/null +++ b/test/validators/isURL.bypass.test.js @@ -0,0 +1,29 @@ +import test from '../testFunctions'; + +describe('isURL – protocol parsing bypass (regression)', () => { + it('require_protocol cases', () => { + test({ + validator: 'isURL', + args: [{ require_protocol: true }], + valid: [ + 'https://example.com', + 'http://example.com/path?x=1#y', + ], + invalid: [ + 'https:example.com', + 'http:example.com', + 'data:text/html,x', + ['java', 'script:alert(1)'].join(''), + ], + }); + }); + + it('protocol-relative cases', () => { + test({ + validator: 'isURL', + args: [{ allow_protocol_relative_urls: true }], + valid: ['//example.com'], + invalid: ['//user:pass@example.com'], + }); + }); +});