Spring Batch Denial of Service — CVE-2026-47881
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
Spring Batch is a lightweight batch processing framework for the JVM. It provides reusable functions for reading, transforming, and writing large volumes of records, together with job and step orchestration, chunk-oriented processing, transaction management, and the restart, skip, and retry semantics that long-running batch jobs depend on.
A Denial of Service (DoS) vulnerability (CVE-2026-47881) has been identified in FlatFileItemReader, which allows attackers to exhaust the heap and saturate a CPU core of a batch application by supplying an input file whose logical record is never terminated.
Per OWASP: The Denial of Service (DoS) attack is focused on making a resource (site, application, server) unavailable for the purpose it was designed. There are many ways to make a service unavailable for legitimate users by manipulating network packets, programming, logical, or resources handling vulnerabilities, among others.
This issue affects flat file reading in the spring-batch-infrastructure module of Spring Batch.
Details
Module Info
- Product: Spring Batch
- Affected packages:
org.springframework.batch:spring-batch-infrastructure - Affected versions: >=6.0.0 <=6.0.4, >=5.2.0 <=5.2.6, >=5.1.0 <=5.1.3, >=4.3.0 <=4.3.13
- GitHub repository: https://github.com/spring-projects/spring-batch
- Published packages: https://central.sonatype.com/artifact/org.springframework.batch/spring-batch-infrastructure
- Package manager: Maven
- Fixed in
- NES for Spring Batch: nes-v4.3.21, nes-v5.1.12, and nes-v5.2.8
- OSS Spring Batch: 6.0.5
Vulnerability Info
This Medium-severity vulnerability is found in the org.springframework.batch:spring-batch-infrastructure package in the flat file reading support of Spring Batch.
FlatFileItemReader supports logical records that span several physical lines by delegating to a RecordSeparatorPolicy. After each line is read, the reader asks the policy whether the accumulated text is a complete record, and if it is not, it reads another line and folds it into the accumulation. The loop that performs this folding has no bound on how many lines it will absorb and no bound on how large the accumulated record may grow.
private String applyRecordSeparatorPolicy(String line) throws IOException {
String record = line;
while (line != null && !recordSeparatorPolicy.isEndOfRecord(record)) {
line = this.reader.readLine();
if (line == null) {
if (StringUtils.hasText(record)) {
// A record was partially complete since it hasn't ended but
// the line is null
throw new FlatFileParseException("Unexpected end of file before record complete", record,
lineCount);
}
else {
// Record has no text but it might still be post processed
// to something (skipping preProcess since that was already
// done)
break;
}
}
else {
lineCount++;
}
record = recordSeparatorPolicy.preProcess(record) + line;
}
return recordSeparatorPolicy.postProcess(record);
}
The termination condition is entirely controlled by the content of the file being read. DefaultRecordSeparatorPolicy reports end of record only when the accumulated text contains no unterminated quote and no continuation marker, so a single unbalanced quote character anywhere in an input file means the policy never reports end of record. JsonRecordSeparatorPolicy behaves the same way for an unbalanced brace. In either case the reader keeps folding lines until it reaches the end of the file, so the rest of the file is assembled into one logical record.
Two costs follow from that. The accumulation is performed with String concatenation, which allocates and copies the entire record on every iteration, so the work is quadratic in the number of folded lines. The record itself grows until it holds the remainder of the file in memory as a single character sequence. A batch job that ingests an attacker-supplied or otherwise untrusted file therefore pins a CPU core and can exhaust the heap with an OutOfMemoryError long before the reader reaches the end of the input, taking down the job and any application hosting it. Deployments that keep the default SimpleRecordSeparatorPolicy, which treats every physical line as a complete record, do not reach the folding path and are not affected.
Mitigation
Only recent versions of Spring Batch receive community support. Older lines are End-of-Life and will not receive public updates to address this issue.
Users of the affected components should apply one of the following mitigations:
- Upgrade to a currently supported version of Spring Batch.
- Leverage a commercial support partner like HeroDevs for post-EOL security support.