CVE-2026-10142
A crafted frame can cause a DoS in kafka-python via memory exhaustion.
- CVSS 8.7
- CWE-789
- Input Validation and Sanitization
- Remote
kafka-python prior to 2.3.2 contains a denial-of-service vulnerability in the protocol parser that allows a malicious broker or machine-in-the-middle attacker to exhaust memory or hang connections by sending a crafted 4-byte frame length value without bounds validation. Attackers can send a specially crafted frame length through the receive_bytes() function to trigger either a multi-gigabyte memory allocation or an uncaught ValueError that leaves the connection in a broken state, causing requests to hang and consumers to stop heartbeating until restart.
- CWE
- CWE-789
- CVSS base score
- 8.7
- Published
- 2026-06-10
- OWASP
- A08 Software and Data Integrity Failures
- Orthogonal defect classification
- Checking
- Code defect classification
- Missing Check
- Category
- Input Validation and Sanitization
- Subcategory
- Insecure Parsing or Deserialization
- Accessibility scope
- Remote
- Impact
- Denial of Service (DoS)
- Affected component
- kafka-python
- Fixed by upgrading
- Yes
Solution
Upgrade kafka-python to version 2.3.2 or later.
Vulnerable code sample
import struct
# This code represents a simplified version of the vulnerable logic
# that could have existed in a network protocol parser.
def receive_bytes(sock):
"""
Reads a 4-byte size prefix and then the full message from a socket.
This function is vulnerable because it does not validate the size
read from the socket before attempting to receive the message payload.
"""
# Read the 4-byte frame length from the remote endpoint.
size_bytes = sock.recv(4)
if not size_bytes or len(size_bytes) < 4:
raise IOError("Incomplete frame size received from broker")
# Unpack the frame length as a big-endian signed 32-bit integer.
# The '>i' format specifier is for a signed integer.
length, = struct.unpack('>i', size_bytes)
# VULNERABLE STEP: The 'length' is used directly without any bounds
# checking.
# 1. If an attacker provides a large positive value (e.g., 0x7FFFFFFF),
# this will attempt a multi-gigabyte memory allocation, causing a
# MemoryError and a denial of service.
# 2. If an attacker provides a negative value (e.g., 0xFFFFFFFF -> -1),
# sock.recv() will raise a ValueError. If this exception is not
# handled by the caller, the connection can be left in a broken
# state, causing subsequent operations to hang.
return sock.recv(length)Patched code sample
import struct
# In a real client, this would be a configurable value, e.g., `max_request_size`.
# We set a reasonable default limit to prevent enormous memory allocations.
MAX_FRAME_SIZE = 100 * 1024 * 1024 # 100MB
def receive_bytes(sock):
"""
Reads a 4-byte length-prefixed frame from a socket-like object.
This function represents a fixed version of the vulnerable code.
"""
# Read the 4-byte frame length prefix.
size_bytes = sock.read(4)
if not size_bytes or len(size_bytes) < 4:
# Not enough data to read size, indicating a closed or broken connection.
return None
# Unpack the size as a big-endian 32-bit signed integer.
(size,) = struct.unpack('>i', size_bytes)
# --- FIX STARTS HERE ---
# The vulnerability was the absence of the following two checks.
# 1. FIX: Disallow negative sizes. A negative value would cause a
# ValueError in sock.read(size) and could leave the connection
# in a broken, un-reusable state.
if size < 0:
raise ValueError(f"Invalid frame size received: {size}. Must be non-negative.")
# 2. FIX: Enforce a maximum frame size. This prevents a malicious actor
# from sending a very large positive number (e.g., 2GB) to trigger
# a massive memory allocation, leading to a MemoryError and DoS.
if size > MAX_FRAME_SIZE:
raise ValueError(
f"Frame size {size} exceeds the configured maximum of {MAX_FRAME_SIZE}."
)
# --- FIX ENDS HERE ---
# If the size is valid and within bounds, safely read the payload.
payload = sock.read(size)
# It's also good practice to check if the full payload was received.
if len(payload) < size:
raise IOError("Connection closed prematurely while reading frame payload.")
return payloadPayload
import struct
# Payload to cause an uncaught ValueError by specifying a negative length (-1)
# This is sent as the 4-byte frame length.
payload = struct.pack('>i', -1)
Cite this entry
@misc{vaitp:cve202610142,
title = {{A crafted frame can cause a DoS in kafka-python via memory exhaustion.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-10142},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-10142/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
