From 445ea01e7a98d5c06b3db944275823bdce7b417a Mon Sep 17 00:00:00 2001 From: koding88 Date: Mon, 24 Aug 2026 23:34:58 +0700 Subject: [PATCH] fix(isURL): evaluate host whitelist against the actual host of bracketed URLs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The early host_whitelist branch checked 'host', which is the empty string whenever the URL target is a bracket-wrapped host like '[::1]' — the real address lives in the 'ipv6' variable at that point. Two consequences: - whitelisted bracketed hosts ('http://[::1]' with host_whitelist: ['::1']) were always rejected; - a whitelist entry matching the empty string (e.g. /^$/ or /.*/) accepted arbitrary bracketed garbage hosts without any IP check, because the whitelist result was returned before host validation. Resolve the effective host with 'host || ipv6' before the check. Plain-domain behavior, including the legacy early-return semantics that let users allowlist non-FQDN hosts such as 'localhost', is unchanged. Regression tests fail before this change and pass after it; the full suite passes with line coverage unchanged at 100%. --- src/lib/isURL.js | 6 +++++- test/validators.test.js | 31 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/lib/isURL.js b/src/lib/isURL.js index 600a91dec..303e715c8 100644 --- a/src/lib/isURL.js +++ b/src/lib/isURL.js @@ -246,7 +246,11 @@ export default function isURL(url, options) { } if (options.host_whitelist) { - return checkHost(host, options.host_whitelist); + // `host` is '' for bracket-wrapped hosts like '[::1]'; the actual + // target lives in `ipv6`. Evaluate the whitelist against it too, + // otherwise whitelisted bracketed hosts are always rejected and an + // empty-matching whitelist regex accepts arbitrary bracketed hosts. + return checkHost(host || ipv6, options.host_whitelist); } if (host === '' && !options.require_host) { diff --git a/test/validators.test.js b/test/validators.test.js index 98d2a12ff..25a482cdd 100644 --- a/test/validators.test.js +++ b/test/validators.test.js @@ -879,6 +879,37 @@ describe('Validators', () => { }); }); + it('should evaluate the host whitelist against bracketed IPv6 hosts', () => { + test({ + validator: 'isURL', + args: [{ + host_whitelist: ['::1', /^2001:/], + }], + valid: [ + 'http://[::1]', + 'http://[::1]:8080', + 'http://[2001:db8::1]/', + ], + invalid: [ + 'http://example.com', + 'http://qux.com', + ], + }); + }); + + it('should not let an empty-matching whitelist regex accept bracketed garbage hosts', () => { + test({ + validator: 'isURL', + args: [{ + host_whitelist: [/^$/], + }], + valid: [], + invalid: [ + 'http://[not-an-ip]', + ], + }); + }); + it('should let users specify a host blacklist', () => { test({ validator: 'isURL',