CVE-2026-47878

Remote Code Execution
Affects
Spring Batch
in
Spring
No items found.
Versions
<=5.2.6, >=6.0.0 <=6.0.4
Exclamation circle icon
Patch Available

This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.

Overview

Spring Batch is a lightweight, comprehensive framework for building batch processing applications on the JVM. It provides reusable functions for handling large volumes of records, including job and step orchestration, chunk-oriented processing, transaction management, skip and retry policies, and restartability. Restartability depends on a job repository that persists job metadata and the execution context of every job and step, and the JDBC job repository stores that execution context as serialized data in a relational database.

A Remote Code Execution (RCE) vulnerability (CVE-2026-47878) has been identified in the DefaultExecutionContextSerializer used by the JDBC job repository, which allows attackers who can influence the stored execution context data to have arbitrary Serializable classes from the application classpath instantiated during deserialization, enabling gadget-chain attacks that can escalate to code execution in the batch application.

Per OWASP: The application deserializes untrusted data without sufficiently verifying that the resulting data will be valid. Data which is untrusted cannot be trusted to be well formed. Malformed data or unexpected data could be used to abuse application logic, deny service, or execute arbitrary code, when deserialized.

This issue affects the job repository execution context serialization of Spring Batch. The MongoDB job repository backend and the ResourcelessJobRepository do not use this serializer and are not affected.

Details

Module Info

Vulnerability Info

This Medium-severity vulnerability is found in the org.springframework.batch:spring-batch-core package in the job repository serialization support of Spring Batch.

Every time a job or step execution is loaded from the JDBC job repository, the persisted execution context is read back through DefaultExecutionContextSerializer. The deserialize method wraps the incoming stream in a Base64 decoder, hands the decoded bytes straight to a plain ObjectInputStream, and calls readObject on it. No ObjectInputFilter is installed on that stream, so the class of every object in the encoded graph is resolved and instantiated without any restriction:

@SuppressWarnings("unchecked")
@Override
public Map<String, Object> deserialize(InputStream inputStream) throws IOException {
	var decodingStream = Base64.getDecoder().wrap(inputStream);
	try {
		var objectInputStream = new ObjectInputStream(decodingStream);
		return (Map<String, Object>) objectInputStream.readObject();
	}
	catch (IOException ex) {
		throw new IllegalArgumentException("Failed to deserialize object", ex);
	}
	catch (ClassNotFoundException ex) {
		throw new IllegalStateException("Failed to deserialize object type", ex);
	}
}

Because the stream is unconstrained, any Serializable type present on the application classpath can be reached, including types whose readObject, readResolve, or finalization logic performs side effects. An attacker who can write to the BATCH_JOB_EXECUTION_CONTEXT or BATCH_STEP_EXECUTION_CONTEXT tables, or who can otherwise influence the bytes that end up in the execution context, can plant a crafted object graph that executes attacker-chosen behavior the next time the job repository reads that execution. Typical exposure paths are a shared or multi-tenant job repository database, a compromised database account with narrow write access, and job parameters or step data that are copied into the execution context from an external source.

Earlier supported lines carry the same unrestricted deserialization through a different call shape. On the 4.3 line the serializer holds a Spring core Deserializer and delegates to it, and that delegate builds a ConfigurableObjectInputStream and calls readObject on it with no filter, so the underlying exposure is identical:

public Map<String, Object> deserialize(InputStream inputStream) throws IOException {
	return (Map<String, Object>) deserializer.deserialize(inputStream);
}

The remedy in both shapes is the same: constrain the object input stream with an allowlist filter that accepts only the JDK types and Spring Batch domain types an execution context legitimately holds, rejecting everything else before any object graph is materialized. Applications that store their own types in the execution context need to extend that allowlist with the classes they persist: setObjectInputFilter on the 5.x and later shape, and setFilterPattern on the 4.3 shape, which targets Java 8 and so cannot name the JDK filter type in a method signature. On the 4.3 line the JDBC job repository does not select this serializer by default, since Jackson2ExecutionContextStringSerializer is the default there, so exposure on that line requires an application to configure DefaultExecutionContextSerializer explicitly.

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.

Credits

  • No external finder was publicly credited for this issue in the upstream advisory.
Vulnerability Details
Severity
Level
CVSS Assessment
Low
>=0 <4
Medium
>=4 <6
High
>=6 <8
Critical
>=8 <10
Medium
ID
CVE-2026-47878
PROJECT Affected
Spring Batch
Versions Affected
<=5.2.6, >=6.0.0 <=6.0.4
NES Versions Affected
Published date
August 26, 2026
≈ Fix date
August 28, 2026
Category
Remote Code Execution
Vex Document
Download VEXHow do I use it?
Sign up for the latest vulnerability alerts fixed in
NES for Spring
Rss feed icon
Subscribe via RSS
or

By submitting the form I acknowledge receipt of our Privacy Policy.

Thanks for signing up for our Newsletter! We look forward to connecting with you.
Oops! Something went wrong while submitting the form.