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

CVE-2026-59935: Infinite Loop Denial of Service in pypdf via Malformed Inline Images

Amit Schendel
Amit Schendel
Senior Security Researcher

Jul 23, 2026·7 min read·69 visits

Executive Summary (TL;DR)

A denial-of-service vulnerability in the pypdf library prior to version 6.14.2 allows remote attackers to trigger 100% CPU exhaustion. By uploading a crafted PDF containing a non-terminated inline image using ASCII85 or ASCIIHex filters, the library enters an infinite loop during parsing operations.

An infinite loop vulnerability exists in the pypdf library prior to version 6.14.2 when processing malformed PDF inline images that utilize ASCII85 or ASCIIHex decoders. Attackers can exploit this vulnerability by submitting crafted PDF files containing incomplete streams, causing the parsing thread to consume 100% CPU resource indefinitely and leading to Denial of Service.

Vulnerability Overview

The pure-Python PDF manipulation library pypdf is widely integrated into web applications, server-side processing pipelines, and document-parsing services to extract text, manage metadata, and modify PDF pages. A critical vulnerability, tracked as CVE-2026-59935 (GHSA-g867-7843-wf8q), exposes these systems to remote Denial of Service (DoS) attacks. The vulnerability resides specifically within the parsing modules responsible for handling inline image streams inside PDF page content streams.

An inline image block in a PDF file is embedded directly within a page's content stream, surrounded by specialized operators. The parser isolates the image properties and processes the raw stream using designated filter decoders, such as /ASCIIHexDecode (abbreviated /AHx) or /ASCII85Decode (abbreviated /A85). When parsing libraries process user-provided documents, they assume structural conformity, specifically the presence of designated End-Of-Data (EOD) delimiters within these encoded streams.

Because pypdf is implemented in pure Python, any execution thread that enters an infinite loop will lock up that execution context completely. In multi-threaded or synchronous single-process web workers, a single malicious PDF payload can exhaust the application server's CPU allocation, leading to unresponsive API endpoints and total system unavailability. The attack surface is broad, as any feature that extracts text, loads images, or rewires pages is vulnerable if it processes untrusted PDF files.

Root Cause Analysis

The root cause of this vulnerability lies in the stream reader loops within the extract_inline__ascii_hex_decode and extract_inline__ascii85_decode functions defined in pypdf/generic/_image_inline.py. When decoding inline image streams, the parser reads data block-by-block using a buffer of a predetermined size until it identifies the corresponding End-Of-Data (EOD) marker, which is > for ASCIIHex or ~> for ASCII85.

If an attacker generates a PDF content stream where the EOD marker is deliberately omitted, the parser eventually consumes the entirety of the stream and reaches the End-Of-File (EOF) state. At this point, the core read operations within the loop, structured as stream.read(BUFFER_SIZE), begin to return empty byte sequences (b""). In normal operations, an empty buffer triggers an EOF validation check that throws a PdfReadError and exits the processing logic safely.

However, the vulnerable parsing logic combines the bulk stream read with a preliminary execution of read_non_whitespace(stream). If the malformed stream ends with one or more trailing non-whitespace characters (such as dangling ASCII noise), read_non_whitespace reads and returns this single byte. Consequently, the variable data_buffered becomes a non-empty sequence, bypassing the validation check if not data_buffered:. Since the buffer contains data but lacks the expected EOD or End-Image (EI) sequence, the loop executes a stream rewind using stream.seek(-2, 1) to handle possible split boundaries. Because the stream position is rewound by two bytes from the absolute end-of-file, the next iteration reads the exact same trailing byte, encounters EOF on the bulk read, bypasses the check, and seeks backward again. This cycle repeats indefinitely, consuming 100% of the CPU core resources.

Code Analysis

The control flow failure can be traced to how the data buffer was structured prior to version 6.14.2. Below is the vulnerable stream reading logic from pypdf/generic/_image_inline.py:

# Vulnerable implementation in pypdf/generic/_image_inline.py
while True:
    # read_non_whitespace extracts trailing data; stream.read() returns empty bytes at EOF
    data_buffered = read_non_whitespace(stream) + stream.read(BUFFER_SIZE)
    if not data_buffered:
        # This check is bypassed because data_buffered is non-empty due to the trailing character
        raise PdfReadError("Unexpected end of stream")
    pos_tok = data_buffered.find(b">")
    # ... processing tokens ...
    if len(data_buffered) == 2:
        data_out += data_buffered
        raise PdfReadError("Unexpected end of stream")
    # The parser appends slice and seeks backward, creating a permanent pointer loop
    data_out += data_buffered[:-2]
    stream.seek(-2, 1) 

In version 6.14.2, the fix introduces an explicit validation of the bulk stream read status using a Python assignment expression (the walrus operator :=). If stream.read(BUFFER_SIZE) yields an empty sequence, the parser detects that no new data has been read and immediately triggers a termination:

# Patched implementation in pypdf/generic/_image_inline.py
while True:
    # Capture bulk stream read explicitly in read_bytes
    data_buffered = read_non_whitespace(stream) + (read_bytes := stream.read(BUFFER_SIZE))
    # Exit immediately if either no data exists or no new bytes are returned from stream.read
    if not data_buffered or not read_bytes:
        raise PdfReadError("Unexpected end of stream.")
    pos_tok = data_buffered.find(b">")
    # ... downstream processing ...
    if len(data_buffered) == 2:
        data_out += data_buffered
        raise PdfReadError("Unexpected end of stream.")
    data_out += data_buffered[:-2]
    stream.seek(-2, 1)

This control flow can be visualized using the following flow diagram, showing how the loop gets trapped under the vulnerable conditions versus how it terminates safely after the patch:

Exploitation

To exploit this vulnerability, an attacker must construct a PDF file containing a malformed inline image within a page content stream. The vulnerability does not require authentication or specific administrative privileges. The target application simply needs to parse the uploaded document programmatically.

The attack vector involves injecting an inline image dictionary that declares the use of /ASCII85Decode or /ASCIIHexDecode filters, but whose image data section abruptly terminates at EOF without the necessary termination sequence. For an ASCII85-encoded object, this means omitting the ~> sequence. The following content structure showcases a raw malformed block:

BI
/W 16
/H 16
/BPC 8
/CS /RGB
/F [/A85]
ID
Gar8O(o6*i%*56~
e  L
e  L9/ LL9/ L

When a vulnerable pypdf instance processes this object via common text extraction routines or metadata collection runs, the execution flow enters the unpatched decoding loops. The CPU core execution thread immediately spikes to 100% capacity. If multiple concurrent malformed documents are uploaded, they can consume all available processor cores within seconds, creating a total application freeze.

Impact Assessment

The concrete security impact of CVE-2026-59935 is restricted to the availability domain, classified as a high-severity Denial of Service (DoS) flaw. There is no direct mechanism for arbitrary code execution (RCE) or sensitive data extraction within this vulnerability. However, the operational consequences of thread exhaustion are severe for enterprise web architectures.

In typical web architectures, multi-worker servers (e.g., Gunicorn or uWSGI processes) handle synchronous parsing tasks. When an unauthenticated attacker transmits several concurrent malformed PDF streams, they can block all active worker threads. This halts processing for all legitimate incoming traffic, presenting as an unresolvable server-side hang that requires administrative intervention to kill the looping processes.

The vulnerability is assessed with a CVSS v4.0 Base Score of 8.7 (High), reflecting an attack path requiring zero privileges and zero user interaction. The EPSS score is currently recorded at 0.00352 (0.352% probability of active exploitation in a 30-day window), and the vulnerability is not listed in the CISA KEV catalog.

Remediation and Mitigation Guidance

The definitive remediation for CVE-2026-59935 is upgrading the pypdf dependency to version 6.14.2 or higher, which contains the complete EOF check patch. Organizations using older major versions are highly advised to pull the latest packages via standard package management utilities.

In environments where upgrading dependencies requires extensive verification cycles, defensive mitigations can be deployed at the application layer. One effective pattern is to segregate intensive parsing workloads into isolated, non-blocking worker pools (such as Celery or Redis Queue) configured with strict runtime limits. Setting a hard timeout (e.g., 5 seconds) on processing tasks guarantees that any thread trapped in an infinite loop is killed before causing host-wide exhaustion.

Additionally, implementing input validations or deploying Web Application Firewalls (WAF) to inspect multi-part file uploads for anomalous PDF stream properties can help block malformed payloads. However, these checks should be treated as temporary measures until the library can be updated to a patched version.

Official Patches

py-pdf/pypdfGHSA Security Advisory
py-pdf/pypdfDeveloper Pull Request
py-pdf/pypdfOfficial 6.14.2 Release Notes

Fix Analysis (1)

Technical Appendix

CVSS Score
8.7/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
EPSS Probability
0.35%
Top 72% most exploited

Affected Systems

Web applications processing untrusted user-submitted PDF filesData ingestion pipelines utilizing pypdf for text and image extractionMicroservices running vulnerable versions of pypdf (< 6.14.2)

Affected Versions Detail

Product
Affected Versions
Fixed Version
pypdf
pypdf_project
< 6.14.26.14.2
AttributeDetail
CWE IDCWE-835
Attack VectorNetwork
CVSS v4.0 Score8.7
EPSS Score0.00352 (0.352%)
ImpactDenial of Service (Availability)
Exploit StatusProof of Concept (PoC) available
KEV StatusNot Listed

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
T1499.004Endpoint DoS: Application Exhaustion
Impact
CWE-835
Loop with Unreachable Exit Condition ('Infinite Loop')

The program contains a loop that can never exit, or that can only exit under extremely rare conditions, due to a bug or an unexpected state.

Vulnerability Timeline

Pull Request #3892 containing the fix is submitted and merged
2026-06-23
pypdf version 6.14.2 is officially released
2026-06-23
GitHub Security Advisory GHSA-g867-7843-wf8q is published
2026-07-08
CVE-2026-59935 is synchronized and published to CVE.org
2026-07-08

References & Sources

  • [1]pypdf GitHub Security Advisory
  • [2]NVD Vulnerability Detail
  • [3]CVE Global 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

•1 day ago•CVE-2026-107844
5.3

CVE-2026-107844: Path Traversal Vulnerability in Contao ImagesController

A path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.

Amit Schendel
Amit Schendel
8 views•5 min read
•1 day ago•CVE-2026-107848
3.5

CVE-2026-107848: Cross-Site Request Forgery (CSRF) in Contao Backend Actions via GET Requests

Contao Open Source CMS versions 4.0.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 contain a Cross-Site Request Forgery (CSRF) vulnerability in backend parameter handling. The `RequestTokenListener` component validates anti-CSRF tokens solely for HTTP POST requests, while GET-based declarative guards run only when an `act` parameter is present in the query string. Consequently, custom backend actions dispatched via alternative parameters such as `key=` can execute without CSRF token verification when triggered by an authenticated user.

Amit Schendel
Amit Schendel
8 views•5 min read
•1 day ago•CVE-2026-107843
5.3

CVE-2026-107843: Unthrottled Activation Email Resend and Account Enumeration in Contao CMS

Contao CMS versions 4.1.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 fail to validate form submission tokens and enforce rate limiting when processing activation email resend requests via HTTP POST, enabling resource exhaustion and account state enumeration.

Amit Schendel
Amit Schendel
8 views•4 min read
•2 days ago•CVE-2026-107842
5.3

CVE-2026-107842: Information Disclosure via Stale Indexing in Contao Search Module

An information disclosure vulnerability in Contao CMS allows unauthenticated site visitors to view protected page titles, URLs, and text excerpts through search queries when protected page indexing is disabled after previously being enabled.

Amit Schendel
Amit Schendel
10 views•4 min read
•2 days ago•GHSA-G38J-7V97-X298
6.5

GHSA-G38J-7V97-X298: Missing Authorization Check in Vikunja CalDAV Task Relation Creation

In Vikunja prior to version 2.6.0, relation creation via the CalDAV endpoint fails to invoke the TaskRelation.CanCreate authorization check. This missing access control allows an authenticated user to establish unauthorized relationships and perform write operations against any task, provided its unique identifier (UID) is known.

Alon Barad
Alon Barad
12 views•5 min read
•2 days ago•GHSA-3HC7-R24J-RPWC
6.8

GHSA-3hc7-r24j-rpwc: Cross-Project Task Disclosure via Subtask Expansion in Vikunja

A cross-project information disclosure vulnerability in Vikunja allows authenticated users with read access to one project to view private task details from unauthorized projects via subtask expansion parameters.

Alon Barad
Alon Barad
9 views•5 min read