CVE-2026-3308:mupdf: Integer overflow in pdf_load_image_imp stride/size computati
A reconstruction of the flaw, and the evidence path Lachesis follows to make it visible.
With no family and no line seeded, the whole-taxonomy enumerator put its class-matched lead inside pdf-image.c:724 (pdf_load_image_imp) -- the sink CVE-2026-3308 is.
That is the shape of the failure. The rest of this case file follows the evidence behind it.
What was known.
What Lachesis established.
Known before Lachesis ran
The CVE and vulnerable release were selected from public history. We are not claiming novel discovery.
- CVE
- CVE-2026-3308
- Vulnerable target
- 1.27.0 (last-vulnerable) · vulnerable
- Prior knowledge
- CVE-2026-3308 · 1.27.0 (last-vulnerable) is vulnerable
Independent re-detection
The experiment graph was built around the last-vulnerable release (1.27.0), scoped to source/pdf + source/fitz + include, so the vulnerable translation unit builds under the pass budget (build 195s, enrich 52232 nodes / 255104 edges), then enumerated BLIND over the whole constructor registry (no family hard-coded, no target line seeded). The census and candidate ids below are the enumerator's own verbatim output; prose in adjudication/trace is MY reading of the advisory + fix, clearly separated from tool output.
- Seeded inputs
- None
- Run timestamp
- 2026-09-03T00:00:00Z
- Evidence artifact
- cve-2026-3308.kuzu (built from mupdf 1.27.0, scoped to source/pdf + source/fitz + include; graph + sidecars deleted after capture)
The commands and outputs below come from this recorded Lachesis run.
What Lachesis reconstructed.
One historical repository. Four captured queries. A complete source-to-sink argument.
Lachesis follows the same evidence path through unfamiliar repositories.
Here is how the path becomes visible.
These are the recorded questions Lachesis asked of the historical vulnerable code, followed by the raw result and source location each query returned.
Captured runA real replay of Lachesis over the graph we built for this case (build 195s under the pass cap, bounded memory). Every value below is verbatim captured tool output; the graph was released immediately after capture.
Investigate the candidate
The narrowed scope builds the vulnerable TU under the pass cap.
build rc=0 195s
enrich rc=0 :: pass2 published 52232 nodes and 255104 edgesA small line with a large consequence.
the guard checks w/h/bpc against SIZE_MAX individually, but the stride and total-size arithmetic uses int, so the product can overflow to a small value that passes and then undersizes the buffer the copy fills.
/* pdf_load_image_imp: stride/size computed in int; undersized buffer filled by fz_unpack_stream */
// post-1.27.0 computes the stride/size in size_t with overflow checks so a dimension product that overflows is rejected before allocation.
The original record.
Read the historical advisory and vulnerability record behind this reconstruction.