From 77476c08ad644e04d9787af7d960e7c5f77034a8 Mon Sep 17 00:00:00 2001 From: minwoo-3 Date: Wed, 16 Sep 2026 17:22:12 +0900 Subject: [PATCH] Fix family mismatch crash in IpInetAddressMatcher IpInetAddressMatcher#matches(InetAddress) compared the byte arrays of the two addresses without first checking that they are the same length. When the configured CIDR mask required more full bytes than the shorter of the two addresses had (for example an IPv6 /64 matcher checked against an IPv4 address), and the leading bytes happened to be equal up to the shorter array's length, the comparison loop indexed past the end of the shorter array and threw ArrayIndexOutOfBoundsException instead of returning false, as documented on IpAddressMatcher. Closes gh-19733 Signed-off-by: minwoo-3 --- .../util/matcher/IpInetAddressMatcher.java | 7 +++++++ .../util/matcher/IpInetAddressMatcherTests.java | 15 +++++++++++++++ 2 files changed, 22 insertions(+) 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");