← Reports xaferima.com Español →

Index-out-of-range panics in image renderers

DoS CVSS 6.5 MEDIUM CWE-129: Improper Validation of Array Index pdfcpu/pdfcpu ≤ v0.16.0

GHSA-6524-w46v-6399 · CVE assignment pending

Summary

Missing input validation in pdfcpu's grayscale and Indexed image renderers allows a crafted PDF to crash any application that extracts or renders images. Images with BitsPerComponent values of 9..16 freeze the packed-pixel loop (8/bpc == 0 via integer division), so the pixel counter never advances while the byte cursor walks off the image buffer. Independently, Indexed color-space images with a short lookup palette index out of bounds. Both paths raise an unrecovered index out of range runtime panic, killing the host process — fault.Catch only recovers internal fault.Panic values, not runtime.Error.

Impact

Root Cause

In pkg/pdfcpu/writeImage.go, renderDeviceGrayToPNG() (and its Indexed siblings) runs a packed-pixel loop that assumes bpc divides 8:

// writeImage.go:393 (same shape at 559, 606, 640, 668)
i := 0
for y := 0; y < im.h; y++ {
    for x := 0; x < im.w; {
        p := b[i]   // ← panics once i >= len(b)
        for j := 0; j < 8/im.bpc && x < im.w; j++ { ... x++ }
        i++
    }
}

With bpc > 8, 8/im.bpc == 0: the inner loop never executes, x never advances, and i walks off the end of b. Image validation only rejects bpc <= 0 plus size limits — there is no upper bound on bpc, and the declared ErrUnsupported16BPC error is never raised in the vulnerable version.

The second sink indexes a short Indexed lookup palette without a length check (the CalRGB branch performs no validation at all):

// writeImage.go:606 — renderIndexedRGBToPNG
l := 3 * int(ind)
img.Set(x, y, color.NRGBA{R: lookup[l], G: lookup[l+1], B: lookup[l+2], A: alpha})

Proof of Concept

Two independent crashes, each confirmed at three levels (direct sink, public entry point, end-to-end PDF):

# Sink 1: bpc 9..16
PDFImage{bpc: 9, w: 2, h: 1, Content: 8 bytes}
→ panic: index out of range [8] with length 8

# Sink 2: Indexed/CalRGB with 3-byte palette, first image byte 0xFF
[/Indexed [/CalRGB] 0 <000000>], image byte 0xFF
→ l = 765 on a 3-byte slice
→ panic: index out of range [765] with length 3

# End-to-end: crafted PDF parses cleanly (api.ReadContext OK),
# then api.ExtractImages panics — fault.Catch does not recover it.

The finding was discovered with LLM-assisted review (Strix) and independently replicated with local unit and end-to-end tests against pdfcpu v0.15.0.

Disclosure Timeline

DateEvent
2026-09-21Vulnerability discovered and PoC-confirmed (3-tier local reproduction)
2026-10-03Report submitted via GitHub Private Vulnerability Reporting
2026-10-04Advisory published — GHSA-6524-w46v-6399
Fixed inpdfcpu v0.16.1

Fix

Reject bpc > 8 in the renderer entry point and validate lookup-palette length against the index range:

// Reject unsupported bit depths before the packed loop:
if im.bpc <= 0 || im.bpc > 8 {
    return ErrUnsupportedBitDepth
}
// Validate palette size before indexed lookup:
if len(lookup) < n << bpc {
    return errShortLookupTable
}

Fixed in pdfcpu v0.16.1. Advisory published 2026-10-04; CVE assignment pending.

← Back to all reports