CVE-2026-59278
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
Spring for Apache Kafka applies core Spring Framework concepts to Kafka-based messaging. It provides a KafkaTemplate for publishing records, annotation-driven listener containers for consuming them, and support classes that map Kafka record headers to and from Spring Messaging headers, including JSON encoding of non-string header values. It is published to Maven Central as org.springframework.kafka:spring-kafka.
A Server-Side Request Forgery (SSRF) vulnerability (CVE-2026-59278) has been identified in the default Kafka header mapper, which allows attackers to make a consuming application perform DNS lookups for names of the attacker's choosing by publishing a record whose header type mapping names a java.net address type.
Per OWASP: In a Server-Side Request Forgery (SSRF) attack, the attacker can abuse functionality on the server to read or update internal resources. The attacker can supply or modify a URL which the code running on the server will read or submit data to, and by carefully selecting the URLs, the attacker may be able to read server configuration such as AWS metadata, connect to internal services like http enabled databases or perform post requests towards internal services which are not intended to be exposed.
This issue affects inbound header mapping in the consumer-side components of Spring for Apache Kafka.
Details
Module Info
- Product: Spring for Apache Kafka
- Affected packages:
org.springframework.kafka:spring-kafka - Affected versions: >=2.3.0 <2.8.13, >=2.9.0 <2.9.15, >=3.0.0 <3.3.17, >=4.0.0 <4.0.7, >=4.1.0 <4.1.1
- GitHub repository: https://github.com/spring-projects/spring-kafka
- Published packages: https://central.sonatype.com/artifact/org.springframework.kafka/spring-kafka
- Package manager: Maven
- Fixed in:
- NES for Spring: 2.7.14-spring-kafka-2.7.19, 2.8.11-spring-kafka-2.8.22, 2.9.13-spring-kafka-2.9.24, 3.1.10-spring-kafka-3.1.18, 3.2.10-spring-kafka-3.2.15 and 3.3.16-spring-kafka-3.3.18
- OSS Spring for Apache Kafka 4.0.7 and 4.1.1
Vulnerability Info
This Medium-severity vulnerability is found in the org.springframework.kafka:spring-kafka package in the inbound header mapping of Spring for Apache Kafka.
DefaultKafkaHeaderMapper, the mapper used by default for JSON-encoded record headers whenever Jackson 2 is on the classpath, seeds its trusted-package list with java.net:
private static final List<String> DEFAULT_TRUSTED_PACKAGES = List.of(
"java.lang",
"java.net",
"java.util",
"org.springframework.util"
);
private final Set<String> trustedPackages = new LinkedHashSet<>(DEFAULT_TRUSTED_PACKAGES);When a record is consumed, the mapper reads the Java type of each JSON-encoded header from the spring_json_header_types header, a value written by the producer, and asks trusted() whether that type may be deserialized:
private void populateJsonValueHeader(Header header, String requestedType, Map<String, Object> headers) {
Class<?> type = Object.class;
boolean trusted = false;
try {
trusted = trusted(requestedType);
if (trusted) {
type = ClassUtils.forName(requestedType, null);
}
}
catch (Exception e) {
logger.error(e, () -> "Could not load class for header: " + header.key());
}
...
if (trusted) {
try {
Object value = decodeValue(header, type);
headers.put(header.key(), value);
}trusted() compares only the package portion of the requested type against the trusted list, so any class in a trusted package is accepted:
protected boolean trusted(String requestedType) {
if (requestedType.equals(NonTrustedHeaderType.class.getName())) {
return true;
}
if (TRUSTED_ARRAY_TYPES.contains(requestedType)) {
return true;
}
String type = requestedType.startsWith("[") ? requestedType.substring(2) : requestedType;
if (!this.trustedPackages.isEmpty()) {
int lastDot = type.lastIndexOf('.');
if (lastDot < 0) {
return false;
}
String packageName = type.substring(0, lastDot);
for (String trustedPackage : this.trustedPackages) {
if (packageName.equals(trustedPackage)) {
return true;
}
}
return false;
}
return true;
}Because java.net is trusted out of the box, a requested type of java.net.InetAddress passes this check, the class is loaded, and the header bytes are handed to Jackson. Jackson's deserializer for InetAddress resolves the supplied text with InetAddress.getByName(), so simply consuming the record causes the application to issue a DNS query for a hostname the remote producer chose. That leaks consumer activity and timing to attacker-controlled name servers, allows the attacker to confirm which records a given consumer processed, and lets the attacker drive lookups of names that resolve only inside the consumer's network. The related types Inet4Address, Inet6Address and InetSocketAddress reach the same deserializers, and array forms such as [Ljava.net.InetAddress; are also accepted, because the normalization above strips only the leading array marker before comparing the package. Applications that widen the trusted list, including those that trust all packages with "*", remain exposed for the same reason. In releases that also ship JsonKafkaHeaderMapper, that mapper carries the same default list and the same check.
Mitigation
Only recent versions of Spring for Apache Kafka 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 for Apache Kafka.
- Leverage a commercial support partner like HeroDevs for post-EOL security support.
Credits
- Sharlong Wen (finder)