cbor2 has a Denial of Service via Uncontrolled Recursion in cbor2.loads

Description

Summary

  • The cbor2 library is 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 correctly uses Python's C-API for recursion protection (Py_EnterRecursiveCall), but this mechanism is designed to prevent a stack overflow by raising a RecursionError. In some environments, this exception is not caught, thus causing the service process to terminate.
  • While the library handles moderate nesting, it lacks a configurable, data-driven depth limit independent of Python's global recursion setting. An attacker can supply a crafted CBOR payload containing thousands of nested arrays (e.g., 0x81). When cbor2.loads() attempts to parse this, it hits the interpreter's recursion limit, causing the call to raise a RecursionError.
  • By sending a stream of small (<100KB) malicious packets, an attacker can repeatedly crash worker processes faster than they can be restarted, resulting in a complete and sustained Denial of Service.

Details

  • The vulnerability stems from the recursive design of the CBORDecoder class, specifically how it decodes nested container types like Arrays and Maps.
  • Inside decode_array (and similarly decode_map), the decoder iterates through the number of elements specified in the CBOR header. For each element, it calls self.decode() again to parse the nested item. This recursive call lacks a depth-tracking mechanism.
  • Vulnerable Code Locations:
  • cbor2/decoder.py (Pure Python implementation)
  • source/decoder.c (C extension implementation)
  • Execution Flow:
    1. The cbor2.loads() function initializes a CBORDecoder and calls its decode() method.
    2. The decode() method reads the initial byte and dispatches control to a specific handler based on the major type. For an Array (Major Type 4), it calls decode_array.
    3. decode_array loops and calls self.decode() for each item, leading to deep recursion when parsing a payload like [...[...[1]...]...].

PoC

import cbor2

DEPTH = 1000

payload = b&#x27;\x81&#x27; * DEPTH + b&#x27;\x01&#x27;
print(f&quot;[*] Payload size: {len(payload) / 1024:.2f} KB&quot;)
print(&quot;[*] Triggering decoder...&quot;)

try:
    cbor2.loads(payload)
    print(&quot;[+] Parsed successfully (Not Vulnerable)&quot;)
except RecursionError:
    print(&quot;\n[!] VULNERABLE: RecursionError triggered!&quot;)
except Exception as e:
    print(f&quot;\n[-] Unexpected Error: {type(e).__name__}: {e}&quot;)

Impact

  • Scope: This vulnerability affects any application using cbor2 to parse untrusted data. Common use cases include IoT data processing, WebAuthn (FIDO2) authentication flows, and inter-service communication over COSE (CBOR Object Signing and Encryption).
  • Attack Vector: A remote, unauthenticated attacker can achieve a full Denial of Service with a highly efficient, low-bandwidth attack. A payload under 100KB is sufficient to reliably terminate a Python worker process.

Credit

This issue was discovered by Kevin Tu of TMIR at ByteDance. The patch was developed by @agronholm.

Basic information

Type
reviewed
Severity
high
Advisory on GitHub
Open advisory ↗
Repository advisory
Open repository advisory ↗
Source code
Browse source ↗
Published (advisory)
2026-03-23 20:23:57 UTC
Updated
2026-03-25 20:38:41 UTC
GitHub reviewed
2026-03-23 20:23:57 UTC
NVD published
2026-03-23

EPSS Score

Score Percentile
0.06% 17.16%

CVSS Scores

Base score Version Severity Vector
7.5 3.0
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H Click to expand
Attack vector (AV:N)
Could be attacked over the internet or any normal routed network—not just someone sitting at the machine.
Attack complexity (AC:L)
Once they can reach the bug, pulling it off is straightforward—no weird race conditions or rare setup.
Privileges required (PR:N)
No account or special rights needed—anonymous or random user is enough.
User interaction (UI:N)
Nobody has to click “OK” or open a trap file; it can work without a victim helping.
Scope (S:U)
Damage stays in the same “trust bubble” as the broken component—no big spill into unrelated systems.
Confidentiality (C:N)
Doesn’t really leak secrets in a meaningful way.
Integrity (I:N)
Data isn’t meaningfully altered or forged.
Availability (A:H)
Could take the service down hard or make it unusable for people who depend on it.

Identifiers

CWEs

CWE id Name
CWE-674 Uncontrolled Recursion

Credits

  • romanticpragmatism (reporter)

Affected packages (1)

Vulnerable version ranges and first patched releases as published by GitHub.

Ecosystem Package Vulnerable range First patched Vulnerable functions
pip cbor2 <= 5.8.0 5.9.0

References

cvelogic Threat Intelligence