Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-84309

CVE-2026-84309: pypdf Library DoS Vulnerability

CVE-2026-84309 is a denial of service flaw in pypdf library that allows attackers to craft malicious PDFs causing infinite loops. This post explains its technical details, affected versions, impact, and mitigation steps.

Published:

CVE-2026-84309 Overview

CVE-2026-84309 is an infinite loop vulnerability [CWE-835] in pypdf, a free and open-source pure-Python PDF library. Versions prior to 6.16.0 fail to detect cycles when traversing PDF tree structures during write operations. An attacker can craft a PDF containing a cyclic tree whose /Next links reference each other, causing TreeObject.insert_child in pypdf/generic/_data_structures.py to loop indefinitely. The condition triggers a denial-of-service against any application that writes children into a tree derived from attacker-controlled input. The maintainers fixed the issue in pypdf version 6.16.0.

Critical Impact

A malicious PDF processed by a write code path in pypdf causes an infinite loop, exhausting CPU and hanging the host application.

Affected Products

  • pypdf versions prior to 6.16.0
  • Python applications and services that ingest untrusted PDFs and invoke tree-writing operations
  • Downstream tools and pipelines bundling vulnerable pypdf releases

Discovery Timeline

  • 2026-09-01 - CVE-2026-84309 published to the National Vulnerability Database (NVD)
  • 2026-09-02 - Last updated in NVD database

Technical Details for CVE-2026-84309

Vulnerability Analysis

The defect resides in TreeObject.insert_child inside pypdf/generic/_data_structures.py. The function walks a singly linked list of sibling nodes by following /Next references, expecting the chain to terminate at a node without a /Next entry. When the input PDF is crafted so that a /Next link eventually points back to a previously visited node, the traversal never reaches a terminator. The loop continues forever, consuming a CPU core and preventing the host process from completing the write operation or serving other requests.

Root Cause

The pre-patch code assumed acyclic tree structures and did not track visited nodes during traversal. Because PDF documents can supply arbitrary object graphs, this assumption is violated whenever a malicious writer references an ancestor through /Next. The absence of a visited-set check corresponds to CWE-835 (Loop with Unreachable Exit Condition).

Attack Vector

Exploitation requires the target application to open an attacker-supplied PDF and reach a write path that inserts a child into a tree derived from the document. The attack is local in CVSS terms and requires no privileges or user interaction beyond processing the file. Impact is limited to availability; confidentiality and integrity are not affected. Common scenarios include PDF conversion services, batch document processors, and archival pipelines that merge or annotate user-submitted files.

python
# Patch excerpt: cycle detection added to TreeObject.insert_child
# in pypdf/generic/_data_structures.py
            return child_reference
        prev = cast("DictionaryObject", self["/Last"])

        visited: set[int] = set()
        while prev.indirect_reference != before:
            prev_id = id(prev)
            if prev_id in visited:
                raise LimitReachedError("Detected cycle in tree structure.")
            visited.add(prev_id)
            if "/Next" in prev:
                prev = cast("TreeObject", prev["/Next"])
                continue

            # append at the end
            prev[NameObject("/Next")] = cast("TreeObject", child_reference)
            child_obj[NameObject("/Prev")] = prev.indirect_reference
            child_obj[NameObject("/Parent")] = self.indirect_reference
            if "/Next" in child_obj:
                del child_obj["/Next"]
            self[NameObject("/Last")] = child_reference
            inc_parent_counter(self, child_obj.get("/Count", 1))

Source: pypdf commit c9ba557. The fix records the Python id() of each visited node in a visited set and raises LimitReachedError when a repeat is detected.

Detection Methods for CVE-2026-84309

Indicators of Compromise

  • Python worker processes pinned at 100% CPU while parsing or writing a PDF with pypdf.
  • Long-running or hanging jobs in PDF ingestion pipelines that never emit output or errors.
  • PDF files whose outline, structure, or name trees contain /Next references pointing to earlier siblings or ancestors.

Detection Strategies

  • Inventory application dependencies to identify installations of pypdf earlier than 6.16.0.
  • Add process-level timeouts and CPU quotas around PDF write operations so runaway loops surface as failed jobs.
  • Parse suspect PDFs offline with cycle-aware tooling to flag structural anomalies before submission to production processors.

Monitoring Recommendations

  • Alert on Python processes exceeding CPU or wall-clock thresholds during document processing.
  • Log the file hash, submitter, and size of PDFs that trigger job timeouts to support incident review.
  • Track pypdf version telemetry across build artifacts and container images to confirm patched versions in production.

How to Mitigate CVE-2026-84309

Immediate Actions Required

  • Upgrade pypdf to version 6.16.0 or later across all applications, containers, and virtual environments.
  • Rebuild and redeploy container images that pin an older pypdf release.
  • Enforce timeouts on PDF processing workers to bound the impact of any residual denial-of-service condition.

Patch Information

The fix is available in pypdf release 6.16.0 and merged via pull request #3964. Additional context is provided in GitHub Security Advisory GHSA-jp53-mhqp-8xcg.

Workarounds

  • Isolate PDF write operations in short-lived worker processes with strict CPU and wall-clock limits.
  • Reject or quarantine PDFs from untrusted sources until the library is upgraded.
  • Avoid invoking TreeObject.insert_child on structures derived from user-supplied PDFs on unpatched systems.
bash
# Upgrade pypdf to the patched release
pip install --upgrade 'pypdf>=6.16.0'

# Verify the installed version
python -c "import pypdf; print(pypdf.__version__)"

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.