Skip to content

Security (5/5): outline cycle + XMP entity expansion — CVE-2026-24688, CVE-2026-40260#5

Merged
icanhasmath merged 2 commits into
1.28.6.xfrom
1.28.6-sec-reader-outline-xmp
Jun 23, 2026
Merged

Security (5/5): outline cycle + XMP entity expansion — CVE-2026-24688, CVE-2026-40260#5
icanhasmath merged 2 commits into
1.28.6.xfrom
1.28.6-sec-reader-outline-xmp

Conversation

@icanhasmath

Copy link
Copy Markdown
Collaborator

Part 5 of 5 of the PyPDF2 1.28.6 security backport, targeting 1.28.6.x.

CVE Sev File Fix
CVE-2026-24688 Mod _reader.py Guard outline /Next walk against cycles
CVE-2026-40260 Mod xmp.py Reject XML entity declarations in XMP

Backported from upstream pypdf 6.6.2 / 6.10.0; Py2.7-safe (xml.dom.expatbuilder is available on 2.7). New tests: Tests/test_security_outline.py, Tests/test_security_xmp.py (3). Validated under Python 2.7.18 — no regressions.

🤖 Generated with Claude Code

icanhasmath and others added 2 commits June 18, 2026 12:53
A crafted document outline whose /Next chain loops back to an
already-visited node made PdfReader._get_outlines walk forever (CWE-835).

Track visited node ids; stop (with a warning) on a repeat, and pass a copy
of the visited set into the /First sub-outline recursion so shared
sub-trees still render. The new visited parameter is a trailing keyword
default, so the public signature is unchanged. Mirrors upstream pypdf
6.6.2 (PR py-pdf#3610).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
XmpInformation parsed untrusted XMP metadata with xml.dom.minidom
parseString, which permits XML entity declarations. libexpat blocks
exponential expansion but not quadratic expansion, so a crafted XMP
packet could exhaust memory (CWE-776).

Parse via a namespace-aware ExpatBuilderNS subclass that installs an
EntityDeclHandler rejecting any entity declaration with ExpatError.
Mirrors upstream pypdf 6.10.0 (PR py-pdf#3724); xml.dom.expatbuilder is
available on Python 2.7.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Backport security fixes to the PyPDF2 1.28.6.x line to mitigate two moderate CVEs: (1) prevent infinite loops when traversing cyclic outline /Next chains, and (2) reject XML entity declarations when parsing XMP metadata to prevent entity-expansion DoS.

Changes:

  • Add cycle detection (visited set) to the outline traversal in PdfReader._get_outlines.
  • Replace XMP parsing with an ExpatBuilderNS-based parser that rejects entity declarations.
  • Add regression tests for both CVEs.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
PyPDF2/_reader.py Adds visited-node tracking to stop outline walking on cycles.
PyPDF2/xmp.py Introduces a safe XMP parser that refuses entity declarations.
Tests/test_security_outline.py Adds a regression test ensuring cyclic outlines terminate.
Tests/test_security_xmp.py Adds regression tests verifying normal XMP parses and entity declarations are rejected.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread PyPDF2/_reader.py

@martinPavesio martinPavesio left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good

@icanhasmath icanhasmath merged commit d807a0e into 1.28.6.x Jun 23, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants