From 7e82f6c758270d8c2be84f625e6d41c9926da60a Mon Sep 17 00:00:00 2001 From: luojiyin Date: Sat, 27 Jun 2026 16:45:48 +0800 Subject: [PATCH 1/3] fix(ipaddr): reject :: with zero compression and hextets >4 hex digits --- lib/ipaddr.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/ipaddr.js b/lib/ipaddr.js index 45eecf0..3b4e00f 100644 --- a/lib/ipaddr.js +++ b/lib/ipaddr.js @@ -61,8 +61,9 @@ colonCount--; } - // The following loop would hang if colonCount > parts - if (colonCount > parts) { + // An address must not contain more separators than available parts, + // and :: must compress at least one part. + if (colonCount >= parts) { return null; } @@ -91,7 +92,7 @@ const results = []; for (let i = 0; i < ref.length; i++) { - results.push(parseInt(ref[i], 16)); + results.push(ref[i].length > 4 ? NaN : parseInt(ref[i], 16)); } return results; From b533c7c7b6812981cd10c5dfdee750b80be6044b Mon Sep 17 00:00:00 2001 From: luojiyin Date: Sat, 27 Jun 2026 16:46:01 +0800 Subject: [PATCH 2/3] test(ipaddr): add tests for strict IPv6 validation --- test/ipaddr.test.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/ipaddr.test.js b/test/ipaddr.test.js index d9508df..5d7ba29 100644 --- a/test/ipaddr.test.js +++ b/test/ipaddr.test.js @@ -336,6 +336,18 @@ describe('ipaddr', () => { assert.equal(ipaddr.IPv6.isValid(undefined), false); }) + it('rejects IPv6 parts longer than four hexadecimal digits', () => { + assert.equal(ipaddr.IPv6.isValid('00000::1'), false); + assert.throws(() => ipaddr.IPv6.parse('00000::1')); + }) + + it('rejects compression of zero IPv6 parts', () => { + assert.equal(ipaddr.IPv6.isValid('1:2:3:4:5:6:7:8::'), false); + assert.throws(() => ipaddr.IPv6.parse('1:2:3:4:5:6:7:8::')); + assert.equal(ipaddr.IPv6.isValid('::1:2:3:4:5:6:7:8'), false); + assert.throws(() => ipaddr.IPv6.parse('::1:2:3:4:5:6:7:8')); + }) + it('validates IPv6 addresses in CIDR notation', () => { assert.equal(ipaddr.IPv6.isValidCIDR('::/0'), true); assert.equal(ipaddr.IPv6.isValidCIDR('2001:db8:F53A::1%z/64'), true); From 974c9888bd0d0fca19e9f90f0c997e4e211ad82d Mon Sep 17 00:00:00 2001 From: luojiyin Date: Sat, 27 Jun 2026 17:03:18 +0800 Subject: [PATCH 3/3] test(ipaddr): add IPv4-embedded v6 hextet check and 1-group compression regression guard --- test/ipaddr.test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/ipaddr.test.js b/test/ipaddr.test.js index 5d7ba29..a6d0337 100644 --- a/test/ipaddr.test.js +++ b/test/ipaddr.test.js @@ -339,6 +339,8 @@ describe('ipaddr', () => { it('rejects IPv6 parts longer than four hexadecimal digits', () => { assert.equal(ipaddr.IPv6.isValid('00000::1'), false); assert.throws(() => ipaddr.IPv6.parse('00000::1')); + assert.equal(ipaddr.IPv6.isValid('00000:0:0:0:0:0:1.2.3.4'), false); + assert.throws(() => ipaddr.IPv6.parse('00000:0:0:0:0:0:1.2.3.4')); }) it('rejects compression of zero IPv6 parts', () => { @@ -348,6 +350,11 @@ describe('ipaddr', () => { assert.throws(() => ipaddr.IPv6.parse('::1:2:3:4:5:6:7:8')); }) + it('does not reject compression of exactly one IPv6 part', () => { + assert.equal(ipaddr.IPv6.isValid('1:2:3:4:5:6:7::'), true); + assert.equal(ipaddr.IPv6.isValid('::1:2:3:4:5:6:7'), true); + }) + it('validates IPv6 addresses in CIDR notation', () => { assert.equal(ipaddr.IPv6.isValidCIDR('::/0'), true); assert.equal(ipaddr.IPv6.isValidCIDR('2001:db8:F53A::1%z/64'), true);