diff --git a/core/src/main/java/org/springframework/security/util/matcher/IpInetAddressMatcher.java b/core/src/main/java/org/springframework/security/util/matcher/IpInetAddressMatcher.java index 7f7e338ea2e..f3c885a64f1 100644 --- a/core/src/main/java/org/springframework/security/util/matcher/IpInetAddressMatcher.java +++ b/core/src/main/java/org/springframework/security/util/matcher/IpInetAddressMatcher.java @@ -94,6 +94,13 @@ public boolean matches(@Nullable InetAddress toCheck) { } byte[] remAddr = toCheck.getAddress(); byte[] reqAddr = this.requiredAddress.getAddress(); + if (remAddr.length != reqAddr.length) { + // Different address families (IPv4 vs IPv6): never match, per the class-level + // contract. Without this check, a mask wide enough to exceed the shorter + // array's length throws ArrayIndexOutOfBoundsException instead of returning + // false. + return false; + } int nMaskFullBytes = this.nMaskBits / 8; byte finalByte = (byte) (0xFF00 >> (this.nMaskBits & 0x07)); for (int i = 0; i < nMaskFullBytes; i++) { diff --git a/core/src/test/java/org/springframework/security/util/matcher/IpInetAddressMatcherTests.java b/core/src/test/java/org/springframework/security/util/matcher/IpInetAddressMatcherTests.java index ecac4658249..25e9966db15 100644 --- a/core/src/test/java/org/springframework/security/util/matcher/IpInetAddressMatcherTests.java +++ b/core/src/test/java/org/springframework/security/util/matcher/IpInetAddressMatcherTests.java @@ -111,6 +111,21 @@ void matchesWhenIpv6AndIpv4AddressThenReturnsFalse() throws Exception { assertThat(matcher.matches(InetAddress.getByName("192.168.1.1"))).isFalse(); } + @Test + void matchesWhenIpv6CidrAndIpv4AddressThenReturnsFalse() throws Exception { + // The mask spans more full bytes (8) than the IPv4 address has (4). Without a + // family/length check, walking the byte arrays runs past the shorter one and + // throws ArrayIndexOutOfBoundsException instead of returning false. + IpInetAddressMatcher matcher = new IpInetAddressMatcher("2001:db8::/64"); + assertThat(matcher.matches(InetAddress.getByName("32.1.13.184"))).isFalse(); + } + + @Test + void matchesWhenIpv4CidrAndIpv6AddressThenReturnsFalse() throws Exception { + IpInetAddressMatcher matcher = new IpInetAddressMatcher("192.168.1.0/24"); + assertThat(matcher.matches(InetAddress.getByName("2001:db8::"))).isFalse(); + } + @Test void matchesWhenStringIpv4MatchThenReturnsTrue() { IpInetAddressMatcher matcher = new IpInetAddressMatcher("192.168.1.1");