CVE-2023-51075
Description
hutool-core v5.8.23 was discovered to contain an infinite loop in the StrSplitter.splitByRegex function. This vulnerability allows attackers to cause a Denial of Service (DoS) via manipulation of the first two parameters.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Hutool-core v5.8.23 has an infinite loop in StrSplitter.splitByRegex that causes OOM or stack overflow when given empty string parameters, enabling DoS attacks.
Vulnerability
Description
CVE-2023-51073 affects Hutool-core, a popular Java utility library. The StrSplitter.splitByRegex function in version 5.8.23 contains an infinite loop when called with empty strings for both the str and regex parameters (the first two arguments). This root cause is a missing boundary check for empty inputs, causing the function to never terminate and continuously allocate memory [1].
Attack
Vector and Exploitation
An attacker can trigger this flaw by directly calling StrSplitter.splitByRegex("", "", 0, false, true) or similar combinations where both input strings are empty. The vulnerability requires no authentication, special privileges, or network access beyond the ability to influence the arguments passed to this method. In applications that accept user-controlled strings for splitting (e.g., parsing user input, configuration data), a remote or local attacker can supply empty strings to cause a denial of service [1][2]. The issue is independent of the remaining parameters (limit, ignoreCase, trim).
Impact
Exploitation leads to uncontrolled resource consumption: either an OutOfMemoryError (OOM) due to heap exhaustion (from repeatedly adding to a list in an infinite loop) or a StackOverflowError if infinite recursion occurs. This effectively causes application or service unavailability, making it a classic denial-of-service vulnerability [1].
Mitigation
Status
The Hutool project has fixed this issue in commit 32f2d0bd55defecb869fbf64d940bcc05642accc, which updates StrSplitter.splitByRegex to handle empty string inputs correctly by returning an empty list early [4]. Users should upgrade to a patched version (e.g., 5.8.24 or later). No workaround exists other than avoiding empty string inputs to this function until an upgrade is applied. The CVE has been assigned CVSSv4 metrics, though NVD has not yet provided a score [2].
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
cn.hutool:hutool-coreMaven | < 5.8.24 | 5.8.24 |
Affected products
2- hutool/hutool-coredescription
Patches
132f2d0bd55de修复StrSplitter.splitByRegex使用空参数导致的OOM问题
3 files changed · +40 −16
CHANGELOG.md+2 −1 modified@@ -2,7 +2,7 @@ # 🚀Changelog ------------------------------------------------------------------------------------------------------------- -# 5.8.24(2023-12-11) +# 5.8.24(2023-12-12) ### 🐣新特性 * 【cache 】 Cache增加get重载,可自定义超时时间(issue#I8G0DL@Gitee) @@ -18,6 +18,7 @@ * 【extra 】 修复Archiver 最后一个 Entry 为空文件夹时未关闭 Entry问题(pr#1123@Gitee) * 【core 】 修复ImgUtil.convert png转jpg在jdk9+中失败问题(issue#I8L8UA@Gitee) * 【cache 】 修复StampedCache的get方法非原子问题(issue#I8MEIX@Gitee) +* 【core 】 修复StrSplitter.splitByRegex使用空参数导致的OOM问题(issue#3421@Github) ------------------------------------------------------------------------------------------------------------- # 5.8.23(2023-11-12)
hutool-core/src/main/java/cn/hutool/core/text/finder/PatternFinder.java+9 −2 modified@@ -49,9 +49,16 @@ public TextFinder setNegative(boolean negative) { @Override public int start(int from) { if (matcher.find(from)) { + final int end = matcher.end(); // 只有匹配到的字符串结尾在limit范围内,才算找到 - if(matcher.end() <= getValidEndIndex()){ - return matcher.start(); + if(end <= getValidEndIndex()){ + final int start = matcher.start(); + if(start == end){ + // issue#3421,如果匹配空串,按照未匹配对待,避免死循环 + return INDEX_NOT_FOUND; + } + + return start; } } return INDEX_NOT_FOUND;
hutool-core/src/test/java/cn/hutool/core/text/split/StrSplitterTest.java+29 −13 modified@@ -1,5 +1,6 @@ package cn.hutool.core.text.split; +import cn.hutool.core.collection.ListUtil; import cn.hutool.core.text.StrSplitter; import org.junit.Assert; import org.junit.Test; @@ -15,49 +16,49 @@ public class StrSplitterTest { @Test public void splitByCharTest(){ - String str1 = "a, ,efedsfs, ddf"; - List<String> split = StrSplitter.split(str1, ',', 0, true, true); + final String str1 = "a, ,efedsfs, ddf"; + final List<String> split = StrSplitter.split(str1, ',', 0, true, true); Assert.assertEquals("ddf", split.get(2)); Assert.assertEquals(3, split.size()); } @Test public void splitByStrTest(){ - String str1 = "aabbccaaddaaee"; - List<String> split = StrSplitter.split(str1, "aa", 0, true, true); + final String str1 = "aabbccaaddaaee"; + final List<String> split = StrSplitter.split(str1, "aa", 0, true, true); Assert.assertEquals("ee", split.get(2)); Assert.assertEquals(3, split.size()); } @Test public void splitByBlankTest(){ - String str1 = "aa bbccaa ddaaee"; - List<String> split = StrSplitter.split(str1, 0); + final String str1 = "aa bbccaa ddaaee"; + final List<String> split = StrSplitter.split(str1, 0); Assert.assertEquals("ddaaee", split.get(2)); Assert.assertEquals(3, split.size()); } @Test public void splitPathTest(){ - String str1 = "/use/local/bin"; - List<String> split = StrSplitter.splitPath(str1, 0); + final String str1 = "/use/local/bin"; + final List<String> split = StrSplitter.splitPath(str1, 0); Assert.assertEquals("bin", split.get(2)); Assert.assertEquals(3, split.size()); } @Test public void splitMappingTest() { - String str = "1.2."; - List<Long> split = StrSplitter.split(str, '.', 0, true, true, Long::parseLong); + final String str = "1.2."; + final List<Long> split = StrSplitter.split(str, '.', 0, true, true, Long::parseLong); Assert.assertEquals(2, split.size()); Assert.assertEquals(Long.valueOf(1L), split.get(0)); Assert.assertEquals(Long.valueOf(2L), split.get(1)); } @Test public void splitEmptyTest(){ - String str = ""; + final String str = ""; final String[] split = str.split(","); final String[] strings = StrSplitter.splitToArray(str, ",", -1, false, false); Assert.assertNotNull(strings); @@ -66,7 +67,7 @@ public void splitEmptyTest(){ @Test public void splitNullTest(){ - String str = null; + final String str = null; final String[] strings = StrSplitter.splitToArray(str, ",", -1, false, false); Assert.assertNotNull(strings); Assert.assertEquals(0, strings.length); @@ -77,7 +78,7 @@ public void splitNullTest(){ */ @Test public void splitByRegexTest(){ - String text = "01 821 34567890182345617821"; + final String text = "01 821 34567890182345617821"; List<String> strings = StrSplitter.splitByRegex(text, "21", 0, false, true); Assert.assertEquals(2, strings.size()); Assert.assertEquals("01 8", strings.get(0)); @@ -89,4 +90,19 @@ public void splitByRegexTest(){ Assert.assertEquals(" 345678901823456178", strings.get(1)); Assert.assertEquals("", strings.get(2)); } + + @Test + public void issue3421Test() { + List<String> strings = StrSplitter.splitByRegex("", "", 0, false, false); + Assert.assertEquals(ListUtil.of(""), strings); + + strings = StrSplitter.splitByRegex("aaa", "", 0, false, false); + Assert.assertEquals(ListUtil.of("aaa"), strings); + + strings = StrSplitter.splitByRegex("", "aaa", 0, false, false); + Assert.assertEquals(ListUtil.of(""), strings); + + strings = StrSplitter.splitByRegex("", "", 0, false, true); + Assert.assertEquals(ListUtil.of(), strings); + } }
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4News mentions
0No linked articles in our index yet.