Los cargadores multifotograma de Pillow pueden reutilizar almacenamiento de imagen nativo obsoleto tras transiciones de modo
Resumen
Los cargadores de imágenes multifotograma de Pillow pueden conservar el almacenamiento nativo ImagingCore asignado para un fotograma mientras modifican el mode de imagen en el lado de Python y los mosaicos del decodificador para un fotograma posterior.
Si el fotograma 0 asigna almacenamiento para un modo estrecho como L, y un fotograma posterior con las mismas dimensiones cambia a un modo más amplio como RGB o CMYK, Pillow puede decodificar píxeles más anchos en el búfer nativo estrecho y obsoleto. Esto genera escrituras fuera de límites nativas y caídas del proceso. En la ruta MPO/JPEG, también se demostró ejecución de comandos en perfiles de tiempo de ejecución de Python/Pillow compatibles a través de la ruta documentada ImageSequence.Iterator + frame.load().
Detalles
La causa raíz radica en que ImageFile.load_prepare() solo vuelve a asignar almacenamiento nativo cuando _im is None. No verifica que el almacenamiento nativo retenido ImagingCore siga coincidiendo con self.mode y self.size.
Varias rutas multifotograma de seek() / _open() pueden actualizar self._mode y los mosaicos del decodificador para un fotograma posterior sin invalidar _im. Como resultado, el decodificador escribe o lee según el modo del nuevo fotograma mientras que el almacenamiento nativo todavía pertenece al modo del fotograma anterior.
Superficies afectadas verificadas:
-
PSD
PsdImageFile.seek()puede cambiar del almacenamiento en escala de grises/nativoLa la decodificación de capas RGB conservando_im. Esto produce escrituras fuera de límites nativas controladas por el atacante y caídas reproducibles. -
MPO/JPEG Un archivo MPO manipulado de dos fotogramas puede hacer que el fotograma 0 asigne almacenamiento
L, y luego hacer que el fotograma 1 decodifique datosCMYK/RGBen el almacenamiento retenidoL. La ruta documentadaImageSequence.Iteratoralcanza esto conframe.load(). Se verificaron corrupción de memoria nativa, caídas, comportamiento de sobrelectura y ejecución de comandos de prueba inocuos en Pillow 12.3.0. -
DCX
DcxImageFile.seek()invoca aPcxImageFile._open(), lo que cambia el estado de modo/mosaico sin una protección de modo en el almacenamiento nativo. Un DCX manipulado con fotogramas PCXLy luegoRGBproduce una discrepancia en el almacenamiento retenido y una caída. -
MIC MIC puede invocar directamente a
TiffImageFile._open()y eludir el comportamiento protegido normal de TIFFseek(). Con una transición de fotograma alcanzable basada enNextIFD, esto provoca una discrepancia en el almacenamiento retenido y una caída.
TIFF sirve como un control positivo útil ya que su ruta seek() comprueba tanto el tamaño como el modo antes de reutilizar el almacenamiento.
Impacto
- Caída del proceso / denegación de servicio
- Escritura fuera de límites nativa
- Sobrelectura nativa en la ruta MPO
- Ejecución de comandos en perfiles de tiempo de ejecución coincidentes de Python/Pillow a través de la ruta MPO/JPEG
Impacto en despliegues del lado del servidor:
- En un servicio web local vulnerable que acepte cargas MPO no autenticadas y las procese automáticamente con Pillow, el ataque requiere una sola petición HTTP sin interacción del usuario posterior a la carga.
- La ejecución del marcador de salida de comando inocuo tuvo éxito 10/10 veces.
- El control
_im=Nonefue limpio 10/10 veces.
Evidencia de Reproducción
Versión probada:
Pillow 12.3.0
Entornos de prueba en terminal MPO:
Python 3.12.3 + Pillow 12.3.0, clean PyPI environment:
marker 10/10, control 0/10
Python 3.13.14 + Pillow 12.3.0, prepared profile:
marker 10/10, control 0/10
Prueba de carga web en servidor:
control 1..10: MARKER_MISSING
control_summary ok 0 missing 10 /10
vulnerable 1..10: MARKER_OK marker_output <server-user>
vulnerable_summary ok 10 missing 0 /10
La prueba en terminal emplea únicamente un comando marcador inofensivo; no utiliza reverse shell, persistencia, exfiltración de datos ni comandos arbitrarios seleccionados por el atacante.
Se pueden proporcionar los siguientes artefactos a los mantenedores:
- Fixtures de prueba mínimos de fallo para PSD, MPO, DCX y MIC
- PoC de marcador MPO no armamentizado
- Demostración local de carga web vulnerable
- Registros de geometría gdb/GEF
- Registros de ejecuciones de control
- Propuesta de estructura para pruebas de regresión
Estructura Mínima de Reproducción
Para la ruta MPO, el patrón consumidor vulnerable es:
from io import BytesIO
from PIL import Image, ImageSequence
source = BytesIO(open(path, "rb").read())
image = Image.open(source)
iterator = ImageSequence.Iterator(image)
next(iterator).load()
next(iterator).load()
El formato de la imagen manipulada es:
frame 0: mode L, dimensions W x H
frame 1: same W x H, wider mode such as CMYK
El fotograma 0 asigna almacenamiento nativo L. El fotograma 1 cambia el modo lógico y el estado del decodificador, pero puede reutilizar el almacenamiento nativo anterior. El decodificador del fotograma 1 escribe utilizando el modo más ancho en el almacenamiento estrecho.
Dirección de Corrección Sugerida
Antes de reutilizar el almacenamiento nativo ImagingCore, Pillow debería verificar que dicho almacenamiento sea compatible con el modo lógico y el tamaño actuales de la imagen.
Una protección central en ImageFile.load_prepare() podría comparar el modo y tamaño del almacenamiento nativo frente a self.mode / self.size y asignar nuevo almacenamiento si difieren. Como alternativa, cada ruta de cambio de modo en seek() / _open() debería invalidar explícitamente _im antes de la decodificación.
Precaución: TIFF tiene un comportamiento especializado en el tamaño de mosaicos y ya cuenta con una protección de modo/tamaño, por lo que una corrección central debe evitar regresiones en el manejo del búfer de mosaicos de TIFF.
Créditos
Rotem Kama
Nota Metodológica
Se utilizó análisis asistido por IA para el descubrimiento y el soporte de verificación. Las afirmaciones de este informe se limitan a los artefactos locales, controles y salidas de comandos descritos anteriormente.
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 | >= 11.0.0, < 13.0.0 | 13.0.0 |
Referencias
- https://github.com/python-pillow/Pillow/security/advisories/GHSA-v9pv-5gc8-w2m6
- https://nvd.nist.gov/vuln/detail/CVE-2026-96639
- https://github.com/python-pillow/Pillow/pull/10105
- https://github.com/python-pillow/Pillow/commit/78d97d994579aef81aafe123773d525f40f2522a
- https://github.com/python-pillow/Pillow
- https://github.com/python-pillow/Pillow/releases/tag/13.0.0
- Vector CVSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H- Debilidad (CWE)
CWE-125, CWE-787- Plataforma
- Python (PyPI)
- Paquete
pillow- Publicada
- 22.10.2026
- Actualizado
- 23.10.2026 00:03
Fuentes y licencias · Editado o traducido por DockRay; se mantienen los derechos y las licencias de las fuentes.
OSV / GitHub Advisory Database - GHSA-v9pv-5gc8-w2m6 - 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
- 100
- Primera → última
- 04.2014 10.2026
- Sin corrección
- 0
- Explotada en ataques
- 1
Distribución por gravedad
- Crítica 13
- Alta 58
- Media 27
- 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: 42
antes: 12
-
Los cargadores multifotograma de Pillow pueden reutilizar almacenamiento de imagen nativo obsoleto tras transiciones de modo 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.