🚨 PHP2Shell — RCE Crítico en PHP (CVE-2026-109618 / CVE-2026-109619)

Acción inmediata

Actualizar PHP hoy a 8.5.12, 8.4.27, 8.3.36 o 8.2.35 (publicadas el 21 de octubre de 2026). Son dos RCE sin autenticación en el núcleo de PHP. Si no puedes actualizar, aplicar las mitigaciones temporales de esta nota — reducen exposición, no arreglan la raíz.

Ficha rápida

  • CVEs: CVE-2026-109618 · CVE-2026-109619
  • Tipo: ejecución remota de código (RCE), sin autenticación
  • Severidad reportada: 10.0 inicialmente; el aviso oficial de PHP la califica CVSS v4.0 9.2
  • Afecta: PHP 5.4.0 – 8.5.11 (todas las versiones con session.upload_progress)
  • Corregido en: 8.2.35 · 8.3.36 · 8.4.27 · 8.5.12 (21-oct-2026)
  • Backports: PHP 7.4, 8.0 y 8.1
  • Sin fix oficial: PHP 5.x y 7.1 (EOL)
  • Nombre público: PHP2Shell — ya hay PoC y exploits

🕒 Cronología

FechaEvento
20-oct-2026Filtración en HN/X/Mastodon; Florian Roth (@cyb3rops) confirma dos RCE. Anuncio oficial en php.net.
20-oct (23 hs)Se rumorea que una de las fallas son dos primitivas use-after-free en el heap del gestor session.upload_progress.
21-oct (8 hs)Exploits circulando. Se recomienda desactivar session.upload_progress. Cloudflare publica reglas WAF de emergencia.
21-oct (11 hs)Parches publicados: 8.5.12, 8.4.27, 8.3.36, 8.2.35.
21-octSury.org publica backports para Debian/Ubuntu desde PHP 5.6.

🧬 Las dos vulnerabilidades

CVE-2026-109618 — RCE por corrupción en falta de memoria (OOM)

El manejo de una situación de out of memory puede interrumpir PHP mientras los datos internos de la request están parcialmente inicializados. La limpieza posterior de la request interpreta esos datos inválidos como válidos.

CVE-2026-109619 — RCE por estado global obsoleto

Un estado interno asociado a una request persiste después de que la memoria que lo contenía fue liberada. Una request posterior, atendida por el mismo worker, usa ese estado obsoleto antes de que la inicialización estándar lo restablezca.

La cadena de ataque de PHP2Shell

El gestor session.upload_progress guarda el nombre de archivo proporcionado por el usuario en los datos de sesión sin validación. Además, un session ID enviado en el cuerpo de un POST puede eludir session.use_only_cookies. Combinado con una vulnerabilidad de LFI (local file inclusion) en la aplicación, se llega a ejecución de código.

No es un exploit universal: el investigador describe varias vías. El riesgo sube en apps que ya tienen LFI o deserialización insegura.


📦 Versiones afectadas y corregidas

RamaEstadoVersión
PHP 8.5✅ Corregido8.5.12
PHP 8.4✅ Corregido8.4.27
PHP 8.3✅ Corregido8.3.36
PHP 8.2✅ Corregido8.2.35
PHP 8.1⚠️ Backport mínimo—
PHP 8.0⚠️ Backport mínimo—
PHP 7.4⚠️ Backport mínimo—
PHP 5.x / 7.1❌ EOL, sin fix oficial—

Afectadas: PHP 5.4.0 – 8.5.11, es decir, todas las versiones que incluyen session.upload_progress.

Backports no oficiales

Sury.org (Ondřej Surý) publicó protección para Debian/Ubuntu desde PHP 5.6, incluidas ramas EOL. Son parches de terceros, no del proyecto PHP. Leer el changelog del paquete antes de implementarlos: un backport puede cambiar comportamiento (por ejemplo, desactivar una funcionalidad de la que dependes).


🎯 ¿Quién está en riesgo?

Toda instalación de PHP que procese requests web:

  • PHP-FPM
  • Apache con mod_php ← mayor riesgo: hay exploit demostrado donde una request no autenticada dispara el ataque antes de ejecutar código de la aplicación
  • php-cgi
  • FrankenPHP
  • LiteSpeed

Contexto de exposición: VirusTotal identifica ~5.1 millones de IPs ejecutando PHP y ~3.8 millones con al menos un puerto abierto.


✅ Solución: actualizar

Actualizar a la versión corregida de tu rama. En Debian/Ubuntu el paquete depende de la versión instalada:

# Ver versión actual
php -v
 
# Actualizar paquetes (ejemplo con la rama 8.3)
sudo apt update
sudo apt install --only-upgrade php8.3-fpm php8.3-cli
 
# Reiniciar el servicio correspondiente
sudo systemctl restart php8.3-fpm

Probar antes de producción

Validar la actualización en staging primero. Un cambio de patch de PHP puede romper extensiones o comportamiento específico. En producción, actualizar por olas y con rollback listo.


🛡️ Mitigaciones temporales (si no puedes actualizar ya)

No son un parche

Reducen vectores conocidos, no garantizan seguridad. Aplicar y luego actualizar igual.

General (ambas CVEs)

Desactivar el gestor de progreso de carga en php.ini global y en .user.ini por sitio:

session.upload_progress.enabled = Off
session.upload_progress.cleanup = Off

Reiniciar todos los workers después del cambio. No confiar en ini_set() ni en .user.ini de FPM para esta directiva.

CVE-2026-109618 (OOM)

MedidaDetalle
memory_limit = -1Mejor vía php_admin_value en el pool FPM o en Apache, para que la app no lo sobrescriba. Asegurar que ningún pool/directorio/app imponga un límite finito.
post_max_size bajo8M si no hay uploads; 32M si se necesitan.
upload_max_filesizeSiempre menor que post_max_size.
Límites de proxy/servidorTamaño de request decodificada, número de campos, partes multipart, headers y profundidad de anidamiento. Aplicar también sin Content-Length válido.
Contenedor / cgroupControl de disponibilidad; ideal terminar solo el worker afectado. No usar RLIMIT_AS ni RLIMIT_DATA: provocan el mismo fallo de asignación.

CVE-2026-109619 (estado obsoleto)

MedidaDetalle
session.upload_progress.enabled = 0En php.ini, pool FPM o config del servidor, antes de procesar requests. Reiniciar todos los procesos.
fatal_error_backtraces = 0Solo PHP 8.5. Bloquea la ruta confirmada de backtraces en errores fatales.
Limpiar configs inválidasEliminar configuraciones obsoletas aplicadas por request que generen diagnósticos antes de la inicialización. Ocultarlas con error_reporting, display_errors o @ no sirve.
Corregir fatales y timeoutsIncluye callbacks, cargas/importaciones de archivos y tareas de limpieza accesibles por un atacante.

WAF

Cloudflare publicó reglas WAF de emergencia para los vectores conocidos, disponibles para todos los planes, incluido el gratuito. Son una capa extra, no un reemplazo del parche.


🔍 Detección

process-watcher de Florian Roth:

  • Binario estático para Linux (amd64 / arm64), sin dependencias.
  • Usa eBPF para mostrar todos los procesos que PHP lanza, con líneas de comando completas.
  • Permite terminar procesos específicos (con prueba previa).
  • Es detección, no parche. No ve lo que ocurre dentro de PHP si no se inicia un proceso externo.

La explotación probablemente se manifieste como subprocesos sospechosos. Aislamiento por contenedores + monitorización estricta son las mejores opciones mientras no haya parche.


🧠 Lecciones

  • No confiar en rumores: el CVSS inicial de 10.0 vino de una filtración; el aviso oficial lo fijó en 9.2. Igual de crítico, pero la fuente importa.
  • Los EOL no desaparecen: PHP 5.x/7.1 no tienen fix oficial. Sury.org salvó a muchos con backports, pero son de terceros.
  • Defensa en profundidad: el parche es la solución; WAF, límites de request, cgroups y monitoreo son capas.
  • La cadena importa: PHP2Shell necesita session.upload_progress + una vía de inclusión/deserialización. Revisar también la app, no solo el runtime.

🔗 Enlaces