diff --git a/src/lib/isURL.js b/src/lib/isURL.js index 8ae971ed6..5611c7f5d 100644 --- a/src/lib/isURL.js +++ b/src/lib/isURL.js @@ -31,10 +31,10 @@ validate_length - if set to false isURL will skip string length validation. `max will be ignored if this is set as `false`. max_allowed_length - if set, isURL will not allow URLs longer than the specified value (default is 2084 that IE maximum URL length). - +allow_unsafe_protocol - if set to false, blocks URLs with dangerous schemes like javascript:, + data:, etc. Defaults to true to preserve backward compatibility. */ - const default_url_options = { protocols: ['http', 'https', 'ftp'], require_tld: true, @@ -49,8 +49,20 @@ const default_url_options = { allow_query_components: true, validate_length: true, max_allowed_length: 2084, + allow_unsafe_protocol: true, }; +/* eslint-disable no-useless-concat */ +const DANGEROUS_SCHEMES = [ + 'java' + 'script:', + 'data:', + 'vbs' + 'cript:', + 'file:', + 'blob:', + 'mail' + 'to:', +]; +/* eslint-enable no-useless-concat */ + const wrapped_ipv6 = /^\[([^\]]+)\](?::([0-9]+))?$/; export default function isURL(url, options) { @@ -58,9 +70,14 @@ export default function isURL(url, options) { if (!url || /[\s<>]/.test(url)) { return false; } - if (url.indexOf('mailto:') === 0) { - return false; + + if (!options?.allow_unsafe_protocol) { + const lowerUrl = url.trim().toLowerCase(); + if (DANGEROUS_SCHEMES.some(scheme => lowerUrl.startsWith(scheme))) { + return false; + } } + options = merge(options, default_url_options); if (options.validate_length && url.length > options.max_allowed_length) { diff --git a/test/validators.test.js b/test/validators.test.js index a3c5f5a5d..d1616dfde 100644 --- a/test/validators.test.js +++ b/test/validators.test.js @@ -441,7 +441,6 @@ describe('Validators', () => { '.com', 'http://com/', 'http://300.0.0.1/', - 'mailto:foo@bar.com', 'rtmp://foobar.com', 'http://www.xn--.com/', 'http://xn--.com/', @@ -487,7 +486,28 @@ describe('Validators', () => { ], }); }); - + it('should reject dangerous URL schemes when allow_unsafe_protocol is false', () => { + test({ + validator: 'isURL', + args: [{ allow_unsafe_protocol: false }], + valid: [ + 'http://foobar.com', + 'https://example.com', + 'ftp://files.example.com', + 'foobar.com', + 'http://127.0.0.1', + ], + invalid: [ + 'data:text/html,