ANT-2026-0BETG8WD · poppler
heap-buffer-overflow high
Severity Claude high · Security research firm high · Maintainer -
Discovered by Claude Mythos Preview
Anthropic's analysis, sealed at approval. Disclosure to the maintainer was performed by Ada Logics.
ANT-2026-0BETG8WD: Heap-buffer-overflow in SplashOutputDev::unsetSoftMaskFromImageMask at SplashOutputDev.cc:2688 via crafted PDF tiling pattern with image mask
In poppler's Splash rendering pipeline, SplashOutputDev::tilingPatternFill() allocates a bitmap sized to the pattern tile (line 4361), but setSoftMaskFromImageMask() sizes its softmask to the main page-level bitmap (line 2662). During teardown, unsetSoftMaskFromImageMask() copies the softmask into the tile bitmap's alpha channel using the softmask's larger dimensions as loop bounds (line 2688: dest[c] = src[c]), writing past the end of the heap-allocated tile alpha buffer. An attacker who controls the ratio of page dimensions to tile dimensions in a crafted PDF controls the overflow length. The result is a reliable crash and potential heap-metadata/adjacent-object corruption in any poppler-based viewer or server-side pipeline using the Splash backend.
Target
Project: poppler
Location: SplashOutputDev.cc:2688, unsetSoftMaskFromImageMask()
Technical Details
The tile bitmap's alpha buffer is sized to tile dimensions while the copy loop in unsetSoftMaskFromImageMask() iterates over the (larger) softmask dimensions derived from the main rendering surface — a classic size-source mismatch. ASAN reports a WRITE "0 bytes after 1-byte region", confirming that even a 1-byte tile allocation is overflowed by the page-sized copy loop; the entire fault stack is internal to poppler (SplashOutputDev.cc → Gfx.cc → Page.cc → PDFDoc.cc).
Crash trace (truncated — full trace in attached crash.log):
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 3169505516
INFO: Loaded 1 modules (215908 inline 8-bit counters): 215908 [0x6209f9524340, 0x6209f9558ea4),
INFO: Loaded 1 PC tables (215908 PCs): 215908 [0x6209f9558ea8,0x6209f98a44e8),
/out/page_label_fuzzer: Running 1 inputs 1 time(s) each.
Running: /tmp/poc
EXIT_CODE:1
=== ASAN Report ===
=================================================================
==27==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x770e152e30d1 at pc 0x6209f842429f bp 0x7ffdaa704770 sp 0x7ffdaa704768
WRITE of size 1 at 0x770e152e30d1 thread T0
#0 0x6209f842429e in SplashOutputDev::unsetSoftMaskFromImageMask(GfxState*, std::__1::array<double, 6ul>&) /src/poppler/poppler/SplashOutputDev.cc:2688:21
#1 0x6209f81a92a2 in Gfx::doPatternImageMask(Object*, Stream*, int, int, bool, bool) /src/poppler/poppler/Gfx.cc:2016:10
#2 0x6209f81bb6f5 in Gfx::doImage(Object*, Stream*, bool) /src/poppler/poppler/Gfx.cc:4347:17
#3 0x6209f817877d in Gfx::opXObject(Object*, int) /src/poppler/poppler/Gfx.cc:4157:13
#4 0x6209f819f270 in Gfx::go(Gfx::DisplayType) /src/poppler/poppler/Gfx.cc:649:13
#5 0x6209f819e680 in Gfx::display(Object*, Gfx::DisplayType) /src/poppler/poppler/Gfx.cc:606:5
#6 0x6209f8435c82 in SplashOutputDev::tilingPatternFill(GfxState*, Gfx*, Catalog*, GfxTilingPattern*, std::__1::array<double, 6ul> const&, int, int, int, int, double, double) /src/poppler/poppler/SplashOutputDev.cc:4387:10
#7 0x6209f81a6419 in Gfx::doTilingPatternFill(GfxTilingPattern*, bool, bool, bool) /src/poppler/poppler/Gfx.cc:2217:53
[... 36 more frames — full trace in crash.log]
Reproduction
- Craft a PDF containing a tiling pattern with an embedded image mask, choosing page dimensions larger than tile dimensions to control overflow length
- Deliver the PDF to the victim via email, download, upload-for-processing, etc.
- Victim opens or processes the PDF in a poppler-based application using the Splash backend
- tilingPatternFill() allocates a small tile-sized bitmap; setSoftMaskFromImageMask() then creates a softmask sized to the main page bitmap
- unsetSoftMaskFromImageMask() copies the oversized softmask into the undersized tile alpha buffer, writing past the heap allocation
[No reproducer or sanitizer output attached — request from security-cvd@anthropic.com if needed.]
Acknowledgement
This vulnerability was discovered by Claude, Anthropic's AI assistant, and triaged by the Anthropic security team in collaboration with Anthropic Research. Please direct questions to security-cvd@anthropic.com and reference ANT-2026-0BETG8WD.
Reference: ANT-2026-0BETG8WD
Anthropic CVD Policy: https://www.anthropic.com/coordinated-vulnerability-disclosure
Triage and disclosure were performed by Ada Logics.
- Verdict
- true positive
- Severity
- high
Dates from discovery through public reveal.
- 2026-03-20 Reported to tracker
- 2026-05-14 Patch released
- 2026-05-20 Sent to maintainer
- 2026-08-17 Publicly revealed
SHA-3-512 hash:
396d3abb80ceb62364bcf81905d621fb58a2551cd2741cf303804ff0eb2abce5be0f94658266721a4be6b2de84a8652566ef6fc1cc2902c607532e7d94e76e54
Committed 2026-03-23 21:57 PT
Revealed 2026-08-17 14:15 PT
Verify (download preimage.json)
Show preimage JSON
{
"ant_id": "ANT-2026-0BETG8WD",
"bug_class": "heap-buffer-overflow",
"claude_severity": "high",
"commit_sha": null,
"created_at": "2026-03-20T19:13:13+00:00",
"description": "In poppler's Splash rendering pipeline, SplashOutputDev::tilingPatternFill() allocates a bitmap sized to the pattern tile (line 4361), but setSoftMaskFromImageMask() sizes its softmask to the main page-level bitmap (line 2662). During teardown, unsetSoftMaskFromImageMask() copies the softmask into the tile bitmap's alpha channel using the softmask's larger dimensions as loop bounds (line 2688: dest[c] = src[c]), writing past the end of the heap-allocated tile alpha buffer. An attacker who controls the ratio of page dimensions to tile dimensions in a crafted PDF controls the overflow length. The result is a reliable crash and potential heap-metadata/adjacent-object corruption in any poppler-based viewer or server-side pipeline using the Splash backend.",
"discovered_at": null,
"location": "SplashOutputDev.cc:2688, unsetSoftMaskFromImageMask()",
"poc_sha256": "5df82ac99d754ff1f89333c9f0a34d2f4316fc59ffb89fad5d34a346528728f0",
"preimage_version": 1,
"project": "poppler",
"reproduction": [
"1. Craft a PDF containing a tiling pattern with an embedded image mask, choosing page dimensions larger than tile dimensions to control overflow length",
"2. Deliver the PDF to the victim via email, download, upload-for-processing, etc.",
"3. Victim opens or processes the PDF in a poppler-based application using the Splash backend",
"4. tilingPatternFill() allocates a small tile-sized bitmap; setSoftMaskFromImageMask() then creates a softmask sized to the main page bitmap",
"5. unsetSoftMaskFromImageMask() copies the oversized softmask into the undersized tile alpha buffer, writing past the heap allocation"
],
"technical_details": "The tile bitmap's alpha buffer is sized to tile dimensions while the copy loop in unsetSoftMaskFromImageMask() iterates over the (larger) softmask dimensions derived from the main rendering surface — a classic size-source mismatch. ASAN reports a WRITE \"0 bytes after 1-byte region\", confirming that even a 1-byte tile allocation is overflowed by the page-sized copy loop; the entire fault stack is internal to poppler (SplashOutputDev.cc → Gfx.cc → Page.cc → PDFDoc.cc).",
"title": "Heap-buffer-overflow in SplashOutputDev::unsetSoftMaskFromImageMask at SplashOutputDev.cc:2688 via crafted PDF tiling pattern with image mask",
"vendor_severity": "high"
}