CVE-2026-59307
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
Spring Integration is the Spring portfolio project that brings the Enterprise Integration Patterns to Spring applications. It provides a lightweight messaging framework of channels, endpoints, transformers and routers, together with channel adapters for protocols and technologies such as files, FTP, HTTP, JDBC, JMS, AMQP, SMB and ZeroMQ.
A Remote Code Execution (RCE) vulnerability (CVE-2026-59307) has been identified in JdbcMessageStore, which allows an attacker who can write bytes into the message table to have arbitrary serialized classes deserialized even though the operator configured an allow list that should have rejected them.
Per OWASP: 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 JDBC message store of Spring Integration.
Details
Module Info
- Product: Spring Integration
- Affected packages:
org.springframework.integration:spring-integration-jdbc - Affected versions: >=7.1.0 <7.1.1, >=7.0.0 <7.0.6, >=6.5.0 <=6.5.10, >=6.4.0 <=6.4.12
- GitHub repository: https://github.com/spring-projects/spring-integration
- Published packages: https://central.sonatype.com/artifact/org.springframework.integration/spring-integration-jdbc
- Package manager: Maven
- Fixed in:
- NES for Spring Integration: 6.4.x, 6.5.x
- OSS Spring Integration 7.0.6, 7.1.1
Vulnerability Info
This High-severity vulnerability is found in the org.springframework.integration:spring-integration-jdbc package in the JDBC message store of Spring Integration.
JdbcMessageStore reads persisted messages through a MessageRowMapper that captures the deserializing converter once, when the field is initialized:
private AllowListDeserializingConverter deserializer =
new AllowListDeserializingConverter(JdbcMessageStore.class.getClassLoader());
private boolean deserializerExplicitlySet;
private MessageRowMapper mapper = new MessageRowMapper(this.deserializer);
When the store is a Spring-managed bean, the container calls setBeanClassLoader() as part of the BeanClassLoaderAware contract. That method installs a brand new permit-all converter but leaves the mapper pointing at the old one:
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
if (!this.deserializerExplicitlySet) {
this.deserializer = new AllowListDeserializingConverter(classLoader);
}
}
Every subsequent addAllowedPatterns(...) call registers its patterns on this.deserializer, the instance the mapper no longer holds:
public void addAllowedPatterns(String... patterns) {
this.deserializer.addAllowedPatterns(patterns);
}
The mapper keeps its own private final AllowListDeserializingConverter deserializer and calls convert(...) on it for every row read out of INT_MESSAGE.MESSAGE_BYTES, so the restriction the operator configured is never consulted and no warning is emitted. Anyone able to place bytes in that column, for example through a compromised or shared database account, reaches full Java deserialization of an arbitrary gadget chain while the application appears to be protected by an allow list.
This vulnerability was introduced in 2024 with Spring Integration 6.4.0, when the row mapper began holding its own converter reference.
Mitigation
Only recent versions of Spring Integration 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 Integration.
- Leverage a commercial support partner like HeroDevs for post-EOL security support.