CVE-2026-59278

Server-Side Request Forgery
Affects
Spring for Apache Kafka
in
Spring
No items found.
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
Exclamation circle icon
Patch Available

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

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

Vulnerability Details
Severity
Level
CVSS Assessment
Low
>=0 <4
Medium
>=4 <6
High
>=6 <8
Critical
>=8 <10
Medium
ID
CVE-2026-59278
PROJECT Affected
Spring for Apache Kafka
Versions Affected
>=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
NES Versions Affected
Published date
August 25, 2026
≈ Fix date
August 27, 2026
Category
Server-Side Request Forgery
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.