← Reportes xaferima.com English →

Panics por índice fuera de rango en renderizadores de imagen

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

GHSA-6524-w46v-6399 · Asignación de CVE pendiente

Resumen

La falta de validación de entrada en los renderizadores de imagen en escala de grises e Indexed de pdfcpu permite a un PDF creado a medida crashear cualquier aplicación que extraiga o renderice imágenes. Imágenes con valores BitsPerComponent de 9..16 congelan el bucle de píxeles empaquetados (8/bpc == 0 por división entera), así que el contador de píxeles nunca avanza mientras el cursor de bytes se sale del buffer de imagen. Independientemente, imágenes de espacio de color Indexed con una paleta de lookup corta indexan fuera de rango. Ambos caminos levantan un index out of range panic de runtime sin recuperar, matando el proceso anfitrión — fault.Catch solo recupera valores internos fault.Panic, no runtime.Error.

Impacto

Causa Raíz

En pkg/pdfcpu/writeImage.go, renderDeviceGrayToPNG() (y sus hermanos Indexed) ejecuta un bucle de píxeles empaquetados que asume bpc divide 8:

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

Con bpc > 8, 8/im.bpc == 0: el bucle interno nunca se ejecuta, x nunca avanza, y i camina fuera del final de b. La validación de imagen solo rechaza bpc <= 0 más límites de tamaño — no hay límite superior en bpc, y el error declarado ErrUnsupported16BPC nunca se lanza en la versión vulnerable.

El segundo sumidero indexa una paleta de lookup Indexed corta sin comprobación de longitud (la rama CalRGB no realiza validación alguna):

// 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})

Prueba de Concepto

Dos crasheos independientes, cada uno confirmado en tres niveles (sumidero directo, punto de entrada público, PDF extremo a extremo):

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

# Sumidero 2: Indexed/CalRGB con paleta de 3 bytes, primer byte de imagen 0xFF
[/Indexed [/CalRGB] 0 <000000>], image byte 0xFF
→ l = 765 en un slice de 3 bytes
→ panic: index out of range [765] with length 3

# Extremo a extremo: PDF creado parsea limpiamente (api.ReadContext OK),
# luego api.ExtractImages panics — fault.Catch no lo recupera.

El hallazgo se descubrió con revisión asistida por LLM (Strix) y se replicó independientemente con pruebas unitarias y extremo a extremo locales contra pdfcpu v0.15.0.

Cronología de Divulgación

FechaEvento
2026-09-21Vulnerabilidad descubierta y PoC-confirmado (reproducción local de 3 niveles)
2026-10-03Informe enviado vía GitHub Private Vulnerability Reporting
2026-10-04Aviso publicado — GHSA-6524-w46v-6399
Corregido enpdfcpu v0.16.1

Corrección

Rechazar bpc > 8 en el punto de entrada del renderizador y validar la longitud de la paleta de lookup contra el rango de índice:

// Rechazar profundidades de bit no soportadas antes del bucle empaquetado:
if im.bpc <= 0 || im.bpc > 8 {
    return ErrUnsupportedBitDepth
}
// Validar tamaño de paleta antes de lookup indexado:
if len(lookup) < n << bpc {
    return errShortLookupTable
}

Corregido en pdfcpu v0.16.1. Aviso publicado 2026-10-04; asignación de CVE pendiente.

← Volver a todos los reportes