Neutron, nuestro motor de IA, obtuvo un 97.1% en el benchmark CyberGym de UC Berkeley. Más información

Análisis a fondo

Análisis a fondo

RCE por metadatos PDF en Gotenberg, explotada en la naturaleza (CVE-2026-42589)

Un salto de línea en una clave de metadatos PDF ejecuta código Perl en servidores Gotenberg sin autenticación antes de 8.31.0; siete grupos la explotan.

En resumen

  • Una falla en Gotenberg antes de 8.31.0 permite a un atacante sin autenticación ejecutar comandos del sistema operativo a través del endpoint de metadatos PDF. Un salto de línea dentro de una clave JSON de metadatos divide la entrada de ExifTool en una nueva línea de argumentos, y el flag inyectado -if evalúa expresiones Perl.
  • Gotenberg es una API de conversión a PDF basada en Docker con más de 101 millones de pulls en Docker Hub. Cualquier instancia anterior a 8.31.0 con el puerto 3000 accesible está expuesta, porque el endpoint no exige autenticación.
  • VulnCheck registró 1,358 eventos de explotación desde 128 direcciones IP en 30 días, en al menos siete grupos de atacantes. El aviso de GitHub la califica como Critical CVSS v3.1 9.8, y el catálogo KEV de CISA no la lista al 2026-10-30.
  • Actualice a Gotenberg 8.31.0 o posterior y recree el contenedor. La corrección se publicó en abril de 2026. Vea "¿Cómo lo corrijo?" para qué más cambia 8.31.0, y "¿Cómo compruebo si estuve comprometido?" para los indicadores de VulnCheck.

¿Estoy afectado?

Está expuesto cuando se cumplen todas estas condiciones:

  • Su instancia ejecuta Gotenberg antes de 8.31.0, publicado el 2026-04-17.
  • El puerto de la API, 3000 por defecto, es alcanzable por el atacante. El aviso de GitHub señala que es común en despliegues internos y en la nube.
  • El endpoint /forms/pdfengines/metadata/write está habilitado. Forma parte del módulo pdfengines y ninguna autenticación lo protege.
Rama Versiones afectadas Versión corregida
Registro CVE-2026-42589 (cve.org) Antes de 8.31.0 8.31.0 (2026-04-17)

El tag de Docker Hub gotenberg/gotenberg:8 apuntaba a 8.29.1 cuando se reportó la falla a principios de abril de 2026, así que las instancias que tiraban del tag mayor en ese momento estaban expuestas.

Compruebe lo que realmente se ejecuta, no lo último que descargó:

# Running instance: the API reports its own version
curl -s http://your-gotenberg-host:3000/version

# Container: which image the running container uses
docker inspect <container> --format '{{.Config.Image}}'

# Image tag pinned in the deployment file
grep -R "gotenberg/gotenberg:" docker-compose.yml k8s/ 2>/dev/null

¿Cómo lo corrijo?

  1. Mueva la referencia de imagen a 8.31.0 o posterior, por ejemplo gotenberg/gotenberg:8.31.0 o el tag 8 actual.
  2. Recree el contenedor, no solo descargue la imagen: docker compose up -d --force-recreate gotenberg, o el despliegue equivalente en Kubernetes.
  3. Verifique el resultado con curl -s http://your-gotenberg-host:3000/version.
  4. Restrinja el puerto 3000 a los llamadores que lo necesiten. El endpoint nunca exigió autenticación, así que la ubicación en la red es el control duradero.

Sepa qué más cambia 8.31.0 antes de saltar versiones menores. La versión también endurece las URL salientes al rechazar loopback, RFC1918 y otras direcciones no públicas, da a --webhook-deny-list valores por defecto que bloquean los rangos internos, y deja de publicar las imágenes thecodingmachine/gotenberg. Los flujos que descargan recursos internos o llaman a webhooks internos pueden necesitar flags tras la actualización.

No existe ninguna solución de configuración para la falla de metadatos en sí. La ruta de código vulnerable se ejecuta antes de que cualquier opción se aplique.

¿Cuál es la causa raíz?

Gotenberg pasa a ExifTool las claves de metadatos PDF suministradas por el llamador sin rechazar caracteres de control, de modo que un salto de línea en una clave rompe el protocolo stdin de ExifTool, basado en líneas, en líneas de argumentos elegidas por el atacante.

Gotenberg convierte documentos a PDF con Chromium sin interfaz y LibreOffice. Su módulo pdfengines expone /forms/pdfengines/metadata/write, que acepta un archivo PDF más un objeto JSON de metadatos. El manejador pasa cada clave y valor a ExifTool mediante la biblioteca go-exiftool.

La biblioteca go-exiftool escribe cada par como una línea del stdin de ExifTool:

fmt.Fprintln(e.stdin, "-"+k+"="+str)

La llamada fmt.Fprintln añade un salto de línea tras cada escritura. Cuando la clave JSON del llamador contiene \n, el json.Unmarshal de Go lo conserva como salto de línea literal en la clave del mapa, y la escritura se divide en varias líneas. ExifTool lee cada línea como un argumento separado. Una clave Title\n-if\nsystem('cmd')||1\n-Comment se convierte en la secuencia de argumentos -Title, -if, system('cmd')||1, -Comment=x.

El flag -if de ExifTool evalúa su argumento como una expresión Perl. system('cmd') ejecuta cmd como el proceso de Gotenberg. El aviso acredita el reporte a S-Senhaji.

El módulo ya sabía que algunas claves eran peligrosas. Una lista dangerousTags borraba las claves FileName y Directory, pero usaba coincidencia exacta de cadenas y nunca eliminó ni rechazó caracteres de control, así que la inyección por salto de línea pasaba sin ser tocada.

¿Cómo se explota?

La prueba de concepto del aviso es una única petición HTTP sin autenticación. Escribe la salida de id en un archivo del servidor:

curl -s -o /dev/null -w "HTTP:%{http_code}" \
  -X POST http://TARGET:3000/forms/pdfengines/metadata/write \
  -F 'files=@sample.pdf;type=application/pdf' \
  --form-string $'metadata={"Title\\n-if\\nsystem(\'id>/tmp/pwned\')||1\\n-Comment": "x"}'
# → HTTP:200
# On server: uid=1001(gotenberg) gid=1001(gotenberg) groups=1001(gotenberg),0(root)
  1. El atacante envía por POST un PDF válido más un objeto JSON de metadatos cuya clave contiene saltos de línea incrustados.
  2. Gotenberg deserializa el JSON; la clave conserva sus saltos de línea literales.
  3. go-exiftool escribe la clave en el stdin de ExifTool, partiéndola en líneas de argumentos.
  4. ExifTool procesa -if system('cmd')||1 como una expresión Perl y ejecuta cmd.
  5. El servidor responde HTTP 200 con un PDF válido, así que la petición parece una conversión normal para la supervisión.

La variante de exfiltración del aviso codifica la salida del comando en base64 y la envía a un receptor HTTP fuera de banda, lo que mantiene el intercambio fuera de los registros del servidor.

La telemetría de octubre de VulnCheck muestra qué hacen con esto los operadores reales. Un grupo probó la ejecución con id, leyó la salida de vuelta en los metadatos Subject del PDF de respuesta mediante el operador -Subject<= de ExifTool, y luego descargó un reverse shell en Go llamado cache_base desde tres espejos independientes. El respaldo con Node.js importa: los contenedores de Gotenberg incluyen Node.js para Chromium sin interfaz, así que el atacante conserva un descargador incluso donde faltan wget y curl.

¿Cómo fluye el ataque?

En una frase: el atacante envía una clave de metadatos con saltos de línea, la clave se divide en líneas de argumentos en el stdin de ExifTool, el flag -if inyectado evalúa una llamada Perl system, y el servidor ejecuta el comando mientras devuelve un PDF de apariencia normal.

flowchart LR A["POST con clave JSON
que contiene \n"] --> B["json.Unmarshal conserva
el salto de línea"] B --> C["go-exiftool escribe la clave
en el stdin de ExifTool"] C --> D["El salto de línea divide la línea
en nuevas líneas de argumentos"] D --> E["-if evalúa
system('cmd')||1
como Perl"] E --> F["El comando se ejecuta como el
proceso de Gotenberg"] F --> G["HTTP 200 con un PDF válido:
ninguna señal de error"]

¿Qué puede hacer un atacante?

El atacante ejecuta comandos del sistema operativo como el proceso de Gotenberg. La salida del aviso muestra un proceso uid=1001(gotenberg) gid=1001(gotenberg) groups=1001(gotenberg),0(root): un usuario sin privilegios con el grupo root. El vector CVSS es CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H, con puntuación 9.8.

Las condiciones son mínimas: acceso de red al puerto 3000, sin credenciales, sin interacción del usuario. La respuesta es una conversión exitosa, así que nada en el intercambio HTTP delata el ataque.

Lo que sigue depende del operador. VulnCheck atribuye la actividad observada a al menos siete grupos con objetivos distintos: escaneo básico, criptominería, reverse shells en Python y el reverse shell en Go cache_base. The Hunter's Ledger, citado por VulnCheck, reportó una campaña de criptominería que confirmó unas 200 instancias de Gotenberg explotables e instaló XMRig, bajo el nombre polkitd, en unas 150 de ellas.

Explotación de CVE-2026-42589 en 30 días de telemetría de VulnCheck: 1,127 eventos desde Gran Bretaña, 224 desde Israel y 1,358 en total desde 128 direcciones IP.
Figura 1: Eventos de explotación de CVE-2026-42589 en 30 días de telemetría canaria de VulnCheck, por geografía de origen. Fuente: VulnCheck, 26 de octubre de 2026

¿Por qué funciona la corrección?

La corrección son tres commits del release 8.31.0, todos en el mismo módulo exiftool. El primero rechaza cualquier clave que no sea un nombre de tag simple:

// safeKeyPattern matches legitimate ExifTool tag names: alphanumeric,
// hyphens, underscores, colons, and periods. Rejects control characters
// (especially \n) that would inject stdin arguments via go-exiftool's
// line-based protocol.
var safeKeyPattern = regexp.MustCompile(`^[a-zA-Z0-9\-_.:]+$`)

Cada clave del objeto de metadatos debe ahora coincidir con safeKeyPattern antes de llegar a go-exiftool. Un salto de línea, retorno de carro o cualquier otro carácter de control falla la coincidencia y la petición se rechaza con HTTP 400.

El segundo commit extiende el mismo control a los valores:

func validateMetadataValue(key, value string) error {
    if strings.ContainsAny(value, "\n\r\x00") {
        return fmt.Errorf("write PDF metadata with ExifTool: invalid metadata value for key %q (contains control character): %w", key, gotenberg.ErrPdfEngineMetadataValueNotSupported)
    }
    return nil
}

El tercero elimina los prefijos de grupo de ExifTool como System: antes de la comprobación de tags peligrosos, de modo que System:FileName ya no la evade, y añade FilePermissions a esa lista de bloqueo. Juntos, los tres cierran la ruta de contrabando de argumentos tanto en claves como en valores, que las notas de la versión describen como bloqueo del contrabando de argumentos y del abuso de pseudo-tags del sistema de archivos.

¿Cómo compruebo si estuve comprometido?

VulnCheck publica indicadores para el grupo cache_base. Compruébelos todos:

  • Indicadores de red: contacto con 210.170.22.208 (Japón residencial, la fuente de ataque observada), 39.105.65.32 (servidor Gitea de carga útil, Alibaba Cloud Pekín), 132.145.123.143 (anfitrión de carga útil, Oracle Cloud Tokio), 5.161.100.63 (C2 de un segundo implante, Hetzner), y los dominios ubuntu-repo.strangled[.]net, linux-x86-tcpudp.strangled[.]net, cheeva.strangled[.]net.
  • Patrones de peticiones: peticiones POST a /forms/pdfengines/metadata/write cuyo JSON de metadatos contiene saltos de línea incrustados. Las cargas observadas usaban claves que empezaban por Title\n-if\n y el archivo temporal /tmp/nx_cmd.txt.
  • Artefactos de host: un archivo de bloqueo oculto llamado .cached_db.lock, el implante cache_base, y la variable de entorno PYTHONUNBUFFERED=1 fijada por el implante Go.
  • Hashes de implantes: cache_base MD5 f5a756d13697cdfa69ed795d4468339d, cache_arm64 MD5 c31cd755293844f8ac0802d2c438e701, cache_mips MD5 2b85605660343399a650b8c3745bccb0.
  • Indicadores de otros grupos: XMRig ejecutándose bajo el nombre de proceso polkitd, y descargas de 4thepool_miner.sh, banner_homepage_800x800.jpg desde un bucket S3, o cargas útiles desde 185.132.53.158:81/anonymus/client.

Un resultado en el endpoint de metadatos por sí solo es una pista, no una prueba: los clientes legítimos también escriben metadatos de PDF. El salto de línea dentro de la clave, el archivo temporal y el archivo de bloqueo son las señales que discriminan.

Cronología

  • 2026-04-06 a 2026-04-13: El mantenedor integra los tres commits de endurecimiento de ExifTool en la rama 8.31.0.
  • 2026-04-17: Se publica Gotenberg 8.31.0 con la sanitización de metadatos y el endurecimiento SSRF.
  • 2026-04-30: Se publica el aviso de GitHub GHSA-rqgh-gxv4-6657, con una prueba de concepto funcional.
  • 2026-05-14: Se publica el registro CVE-2026-42589 con el rango afectado.
  • 2026-06-26: VulnCheck añade la falla a su propio catálogo tipo KEV. CISA no la había añadido al 2026-10-30.
  • 2026-08-31: Un grupo XMRig ataca la falla. El sondeo más antiguo observado por VulnCheck, desde direcciones Telecom Italia rotativas, había corrido de finales de junio a principios de agosto.
  • 2026-10-19 a 2026-10-24: El escáner de Contabo 5.189.138.115 genera 364 eventos, más de un cuarto del total de 30 días.
  • 2026-10-26: VulnCheck publica su análisis de la explotación y del implante cache_base.

Corregida en abril, explotada desde finales de junio, analizada en octubre: la cronología de CVE-2026-42589 desde el release hasta el informe de VulnCheck.
Figura 2: La carrera del parche para CVE-2026-42589, desde la corrección 8.31.0 hasta la explotación observada y el análisis de VulnCheck. Fuentes: releases de Gotenberg, el aviso de GitHub y VulnCheck, consultados el 30 de octubre de 2026

Preguntas frecuentes

¿Por qué ningún escáner detectó esto antes de la explotación?

La falla tiene un CVE y un aviso de GitHub, pero los escáneres solo señalan lo que está inventariado. Una imagen de Docker no es una dependencia de paquete, así que los escáneres de dependencias no la ven, y el contenedor sigue convirtiendo PDFs con normalidad. El endpoint de versión es la comprobación fiable.

¿La falla está en ExifTool o en Gotenberg?

El aviso la sitúa en Gotenberg. El comportamiento de -if de ExifTool está documentado, y el protocolo por líneas de go-exiftool es el diseño de la biblioteca. Gotenberg controla lo que entra en ese protocolo, y la lista de bloqueo que ya llevaba muestra que los mantenedores aceptaban esa responsabilidad; la corrección está por completo en el código de Gotenberg.

¿Qué hace el implante cache_base?

Es un binario Go de 5.2 MB sin símbolos que toma un bloqueo, consulta ipinfo.io por la ubicación de la víctima, se conecta a uno de dos C2 y canaliza un shell entre la conexión y /bin/sh. No tiene persistencia propia, pero su kit incluye un vigilante que lo reinicia.

Mi instancia es interna. ¿Sigo siendo objetivo?

Los despliegues internos y en la nube suelen dejar el puerto 3000 accesible, como señala el aviso, y una sola ventana de 30 días contó 1,358 eventos desde 128 direcciones. Un emplazamiento interno reduce quién puede alcanzar el puerto; no elimina la falla. Corrija de todos modos.

¿Debo rotar algo después de corregir?

Si las comprobaciones de compromiso coinciden, trate el host como comprometido: rote todo lo que el proceso de Gotenberg pudiera leer, incluidas credenciales de servicio y claves de API alcanzables desde su entorno, y redespliegue desde la imagen corregida en lugar de limpiar en el sitio.

Encuentre los servidores Gotenberg expuestos con Ostorlab

El descubrimiento de superficie de ataque de Ostorlab inventaría sus hosts y servicios expuestos a Internet, para que encuentre los que exponen una API de conversión de documentos y compruebe sus versiones antes que un atacante.

Referencias

  • Aviso de GitHub GHSA-rqgh-gxv4-6657, CVE-2026-42589, CVSS v3.1 9.8, publicado el 2026-04-30, con la causa raíz y la prueba de concepto: https://github.com/gotenberg/gotenberg/security/advisories/GHSA-rqgh-gxv4-6657 (consultado el 30 de octubre de 2026)
  • Registro CVE-2026-42589, versiones afectadas antes de 8.31.0, publicado el 2026-05-14: https://www.cve.org/CVERecord?id=CVE-2026-42589 (consultado el 30 de octubre de 2026)
  • VulnCheck, "Cache Me If You Can: Unpacking a Go Implant and Its Toolkit", Jacob Baines, 26 de octubre de 2026, los recuentos de explotación, los siete grupos y los indicadores: https://www.vulncheck.com/blog/cache-me-if-you-can (consultado el 30 de octubre de 2026)
  • Notas de la versión 8.31.0 de Gotenberg, publicadas el 2026-04-17, la sanitización de ExifTool y los cambios de ruptura: https://github.com/gotenberg/gotenberg/releases/tag/v8.31.0 (consultado el 30 de octubre de 2026)
  • Commit de corrección 405f1069c026, "fix(exitool) [sic]: prevent control characters", 2026-04-06: https://github.com/gotenberg/gotenberg/commit/405f1069c026 (consultado el 30 de octubre de 2026)
  • Commit de corrección 55d19522a816, "fix(exiftool): prevent line breaks", 2026-04-11: https://github.com/gotenberg/gotenberg/commit/55d19522a816 (consultado el 30 de octubre de 2026)
  • Commit de corrección 46e190970fed, "fix(exiftool): remove System: prefixes", 2026-04-13: https://github.com/gotenberg/gotenberg/commit/46e190970fed (consultado el 30 de octubre de 2026)
  • Repositorio de Gotenberg, 13,478 estrellas el 30 de octubre de 2026: https://github.com/gotenberg/gotenberg (consultado el 30 de octubre de 2026)
  • Gotenberg en Docker Hub, 101,471,977 pulls el 30 de octubre de 2026: https://hub.docker.com/r/gotenberg/gotenberg (consultado el 30 de octubre de 2026)
  • The Hunter's Ledger, la campaña XMRig contra unas 200 instancias de Gotenberg explotables, citada por VulnCheck: https://the-hunters-ledger.com/reports/gotenberg-rce-cryptomining-107-175-69-137/ (consultado el 30 de octubre de 2026)
  • Feed JSON del catálogo KEV de CISA, comprobado para CVE-2026-42589 el 30 de octubre de 2026 (no listado): https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json (consultado el 30 de octubre de 2026)