Seguridad web

CVE-2026-109618 y CVE-2026-109619 (PHP2Shell): causa raíz, verificación real del parche, mitigación temporal y detección

Guía técnica en español de PHP2Shell: causa raíz de ambos CVE, por qué php -v no confirma el parche, comandos por distro, Docker, cPanel y FrankenPHP, mitigación en php.ini y detección en logs.

21 de octubre de 2026·12 min de lectura·Aldama Dev

TL;DR. Dos fallas en el núcleo de PHP, CVSS v4.0 9.2, permiten ejecución remota de código sin autenticación en cualquier instalación que atienda peticiones web: PHP-FPM, Apache con mod_php, php-cgi, FrankenPHP y LiteSpeed. Están afectadas todas las versiones desde PHP 5.4. Corregido en 8.5.12, 8.4.27, 8.3.36 y 8.2.35, publicadas el 21 de octubre de 2026. Hay intentos de explotación reportados. No hay mitigación completa: hay que actualizar y reiniciar todos los workers. php -v no basta para confirmar el parche si usas paquetes de distribución.

CVEAdvisoryClaseCVSS v4.0
CVE-2026-109618GHSA-w8hw-w9fx-j79wCorrupción de memoria por manejo de OOM durante la inicialización del request9.2
CVE-2026-109619GHSA-6wmf-4rv5-p3rpUse-after-free por estado global que sobrevive entre requests del mismo worker9.2

Esta guía es para quien administra servidores, hostings o aplicaciones PHP: qué se rompió exactamente, cómo verificar de verdad que estás parchado en cada tipo de instalación, qué mitigar si no puedes actualizar hoy y qué buscar en los logs. Si necesitas explicárselo a la gerencia o a un cliente, usa la versión para no técnicos.

Cronología

Horas en Colombia (UTC-5).

  • 19 de agosto de 2026: Wiz Research encuentra la primera falla. El 20 confirma RCE sin autenticación contra Drupal y el 21 contra WordPress.
  • 24 de agosto: reporte al equipo de seguridad de PHP. En paralelo, LCFR de Calif.io investiga la misma familia de errores por agotamiento de memoria.
  • 20 de octubre: los IDs de los CVE se filtran en Hacker News y redes. El embargo estaba fijado para el 22. PHP anuncia una publicación adelantada y CERT-EU emite el aviso 2026-018.
  • 21 de octubre, 9:00 a.m.: salen 8.5.12, 8.4.27, 8.3.36 y 8.2.35, más backports mínimos en código fuente para 7.4, 8.0 y 8.1. Cloudflare despliega reglas WAF en todos sus planes y reporta los primeros ataques.

Causa raíz

CVE-2026-109618: OOM con datos a medio inicializar

Según el aviso oficial, el manejo de out-of-memory puede interrumpir PHP mientras los datos internos del request están parcialmente inicializados. Luego, la limpieza del request trata esos datos inválidos como válidos. El disparador típico es el parseo de cuerpos multipart/form-data, que ocurre antes de que se ejecute una sola línea de tu aplicación.

CVE-2026-109619: estado del request que sobrevive al free

Estado propiedad del request sobrevive después de liberar su memoria. Un request posterior atendido por el mismo worker puede usarlo antes de que la inicialización normal lo resetee. Es un use-after-free entre requests, con divulgación de memoria confirmada.

Las variantes que documentó Wiz

  • Unserializer de upload progress: un fallo de asignación al decodificar la sesión de progreso de subida deja BG(unserialize) publicado después de destruir el heap del request.
  • Divulgación de memoria vía cookie: PS(id) puede seguir apuntando a memoria liberada, que un request multipart posterior codifica en una cookie PHPSESSID. Funciona aunque la aplicación nunca llame session_start().
  • Backtrace de error fatal: EG(last_fatal_error_backtrace) no se limpia tras un fatal por OOM y el siguiente request sigue un puntero colgante.
  • Type confusion en OPcache: un fallo de asignación en zend_accel_script_persist() deja CG(map_ptr_last) avanzado en el proceso pero no en la memoria compartida, y otro worker reutiliza el slot con un tipo equivocado. Es la cadena que usaron contra WordPress.

La divulgación de memoria elimina la incertidumbre de direcciones y hace la explotación mucho más confiable. Wiz advierte que probablemente existen más variantes, cubiertas por los mismos dos CVE.

Superficie afectada

  • Todos los SAPI web: PHP-FPM detrás de nginx o Apache, mod_php, php-cgi, FrankenPHP y LiteSpeed.
  • mod_php es el peor caso: PHP validó RCE por HTTP con límites por defecto, y el exploit se dispara antes de que corra código de la aplicación.
  • Más allá de los sitios web: paneles como cPanel y Plesk, aplicaciones de Windows que empaquetan php-cgi.exe y appliances de proveedores. Palo Alto Networks, por ejemplo, reportó productos afectados.
  • Exposición: PHP corre en el 69,3% de los sitios con lenguaje de servidor conocido según W3Techs, y hay estimaciones de más de 1,3 millones de hosts expuestos potencialmente vulnerables.

Estado de parches por rama

RamaVersión corregidaNotas
8.58.5.12Además, fatal_error_backtraces como mitigación temporal.
8.48.4.27Destino recomendado para migraciones.
8.38.3.36
8.28.2.35Fin de soporte de seguridad: 31 de diciembre de 2026.
8.1, 8.0, 7.4Sin release oficialBackports mínimos en código fuente en php-src, o parche del vendor LTS o la distro.
7.3 y anterioresNingunaSin corrección. Aislar o migrar.
8.68.6.0 RC4Incluye las correcciones.

Cómo verificar de verdad que estás parchado

El error más común hoy es confiar en php -v. Hay dos trampas. Primero, el binario CLI puede ser distinto del que atiende la web. Segundo, Debian, Ubuntu y RHEL aplican backports de seguridad sin cambiar la versión upstream: puedes estar parchado con un número “viejo” o vulnerable con uno que parece reciente. Lo que vale es el changelog del paquete.

Qué versión atiende realmente la web

# Versión y SAPI del binario de línea de comandos
php -r 'echo PHP_VERSION, " ", PHP_SAPI, PHP_EOL;'

# Versión del FPM que corre (ajusta el nombre a tu rama)
php-fpm8.3 -v        # Debian/Ubuntu
php-fpm -v           # RHEL/Alma/Rocky

# Lo más confiable: preguntarle al propio servidor web.
# Crea, consulta y BORRA de inmediato:
echo '<?php echo PHP_VERSION, " ", PHP_SAPI;' > /var/www/html/v-$RANDOM.php

Debian y Ubuntu

dpkg -l | grep -E '^ii\s+(php[0-9.]*-(fpm|cgi|common)|libapache2-mod-php)'

# ¿El paquete instalado ya trae el fix? Busca los CVE en el changelog
apt-get changelog php8.3-common | grep -m3 -E 'CVE-2026-10961[89]'

apt-get update && apt-get install --only-upgrade 'php8.3-*'
systemctl restart php8.3-fpm      # PHP-FPM
systemctl restart apache2         # si usas mod_php

RHEL, AlmaLinux y Rocky

rpm -qa 'php*'
rpm -q --changelog php-common | grep -m3 -E 'CVE-2026-10961[89]'

dnf upgrade 'php*'
systemctl restart php-fpm httpd

Si usas el repositorio Remi: PHP advirtió que el día del release no tendría paquetes actualizados. Revisa su estado o cambia a paquetes de la distribución o compila desde fuente.

cPanel y Plesk

# cPanel EasyApache 4: cada versión vive aparte
for v in /opt/cpanel/ea-php*/root/usr/bin/php; do echo "$v: $($v -r 'echo PHP_VERSION;')"; done

Plesk confirmó que todas las versiones de PHP que distribuye están afectadas. Sigue su artículo de soporte sobre estos CVE y verifica cada handler de PHP activo, no solo el predeterminado.

Docker y Kubernetes

# ¿Qué imágenes base usan tus servicios?
grep -rn --include='Dockerfile*' -E '^FROM .*php' .

# Versión real dentro de la imagen desplegada
docker run --rm tu-imagen:tag php -r 'echo PHP_VERSION, PHP_EOL;'

# Reconstruye sin caché sobre la base corregida y redespliega
docker build --pull --no-cache -t tu-imagen:tag .

Un tag fijo como php:8.3.20-fpm nunca recibirá el fix: hay que subirlo explícitamente. Un rebuild sin --pull puede reutilizar la base vieja en caché.

FrankenPHP

PHP va compilado dentro del binario. Necesitas un build de FrankenPHP enlazado contra una versión corregida. Confírmalo con frankenphp version, que muestra la versión de PHP embebida.

Reinicia todos los workers

CVE-2026-109619 vive en estado que persiste dentro del worker. Instalar el paquete sin reiniciar FPM o Apache deja procesos viejos atendiendo tráfico. Reinicia, no hagas solo un reload, y confirma que no queden procesos con fecha de inicio anterior al parche:

ps -eo pid,lstart,comm | grep -E 'php-fpm|apache2|httpd'

Mitigación temporal si no puedes actualizar hoy

El aviso oficial es explícito: no hay mitigaciones completas, solo reducen rutas de ataque conocidas. Úsalas como puente de horas, no de semanas.

Para CVE-2026-109618

Fija memory_limit=-1 de forma que la aplicación no pueda sobrescribirlo, y acota el tamaño de los POST. No uses RLIMIT_AS ni RLIMIT_DATA: provocan precisamente el fallo de asignación vulnerable. Un límite de memoria de contenedor o cgroup protege disponibilidad, no es mitigación.

Para CVE-2026-109619

Desactiva session.upload_progress.enabled y, solo en PHP 8.5, fatal_error_backtraces. Debe aplicarse antes del parseo del request: en php.ini, en el pool de FPM o en la configuración del servidor. ini_set() y .user.ini no sirven.

; PHP-FPM: /etc/php/8.3/fpm/pool.d/www.conf (o el pool de cada sitio)
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 32M        ; 8M si no hay subida de archivos
php_admin_value[upload_max_filesize] = 30M  ; siempre menor que post_max_size
php_admin_flag[session.upload_progress.enabled] = off
php_admin_flag[fatal_error_backtraces] = off ; solo PHP 8.5
# Apache + mod_php (y límites de request en el servidor web)
php_admin_value memory_limit -1
php_admin_value post_max_size 32M
php_admin_flag session.upload_progress.enabled off
LimitRequestBody 33554432
LimitRequestFields 100
# nginx delante de PHP-FPM
client_max_body_size 32m;

Con memory_limit=-1 pierdes el freno por request. Compénsalo con un pm.max_children conservador y los límites de tamaño de arriba para no cambiar un RCE por una caída por memoria. Reinicia todos los workers después.

Otras capas que ayudan: las reglas WAF de Cloudflare, disponibles incluso en el plan gratuito, solo si el origen acepta tráfico únicamente desde Cloudflare. Para sistemas que no se pueden parchar, CERT-EU recomienda sacarlos de la red pública detrás de VPN. Ocultar errores con display_errors, error_reporting o @ no ayuda.

Detección: qué buscar en logs y procesos

Los indicadores que publicaron Wiz y Huntress son de comportamiento. A la fecha no hay IoC confirmados.

  • Requests multipart inusuales seguidos de errores de límite de memoria.
  • Ráfagas de respuestas HTTP 500.
  • Cookies PHPSESSID de respuesta anormalmente grandes o malformadas.
  • Reinicios de workers de PHP sin explicación.
  • Procesos de PHP o del servidor web que lanzan shells, intérpretes o herramientas de descarga.
  • Archivos PHP nuevos en el webroot, cron jobs o cuentas nuevas.
# Errores de memoria agotada
grep -hE 'Allowed memory size of [0-9]+ bytes exhausted' \
  /var/log/php*fpm*.log /var/log/apache2/error.log /var/log/httpd/error_log 2>/dev/null | tail -50

# POST que terminaron en 500 (formato combined de nginx)
awk '$6 ~ /POST/ && $9 == 500' /var/log/nginx/access.log | tail -50

# Hijos sospechosos de PHP o del servidor web
ps -eo pid,ppid,user,args --forest | grep -B1 -E '\b(sh|bash|dash|curl|wget|nc|python3?|perl)\b' \
  | grep -E -A1 'php-fpm|apache2|httpd'

# Archivos PHP creados o modificados desde la filtración
find /var/www -type f -name '*.php' -newermt '2026-10-20' -printf '%TY-%Tm-%Td %TH:%TM %u %p\n' | sort

# Persistencia
crontab -l -u www-data 2>/dev/null; ls -la /etc/cron.d /var/spool/cron 2>/dev/null

# WordPress: administradores y eventos programados
wp user list --role=administrator --fields=ID,user_login,user_email,user_registered
wp cron event list

Para buscar cadenas de reverse shell en procesos o logs: /dev/tcp/, fsockopen y mkfifo. Si no tienes EDR en servidores Linux, Huntress sugiere el process-watcher de Florian Roth en modo observación.

Si encuentras señales de compromiso

  1. Aísla el servidor de la red pública sin apagarlo.
  2. Preserva logs del servidor web y de PHP, y si puedes, un snapshot del disco.
  3. Actualiza PHP en una instancia limpia, no sobre la comprometida.
  4. Rota todos los secretos que el servidor podía leer: usuario de base de datos, salts de WordPress (wp config shuffle-salts), llaves de API, credenciales SMTP, llaves de pasarelas de pago y de la nube.
  5. Revisa webshells, cron, tareas programadas y usuarios nuevos antes de volver a exponerlo.

Aun sin señales, considera rotar secretos en servidores que estuvieron expuestos sin parche desde el 20 de octubre. La divulgación de memoria permite filtrar claves sin dejar rastro de ejecución.

Explotación: qué se sabe hoy

Las fuentes no coinciden del todo. Cloudflare reporta ataques tempranos y watchTowr dice haber reproducido ambas fallas y observado intentos contra las dos. Patchstack reporta incidentes de explotación activa comunicados por proveedores de hosting. Huntress, en cambio, no había visto explotación en su base de clientes al cierre del 21 de octubre. La PHP Foundation dijo que, al momento del release, ninguna de las pruebas de concepto filtradas era funcional. Cuidado con los “exploits” que circulan: varios no están verificados y pueden traer malware.

Prioridad de parcheo

PrioridadSistemas
1. AhoraExpuestos a internet con mod_php, hostings compartidos multi-sitio, cualquier cosa en PHP 7.x o 8.0–8.1.
2. HoyPHP-FPM público: WordPress, WooCommerce, Magento, Drupal, Laravel. Paneles cPanel y Plesk.
3. Esta semanaAplicaciones internas detrás de VPN, workers de colas, imágenes de CI y contenedores de staging.

La lección de fondo: bugs encontrados por IA

Wiz contó que usó Gemini y GPT para encontrar las fallas, adaptar los exploits a distintas versiones y layouts de memoria, y validar el parche. Un investigador hizo en una semana lo que antes tomaba meses a un equipo de primer nivel. Errores de más de una década en el núcleo de PHP salieron a la luz en días.

Esa misma capacidad está al alcance de los atacantes. Las ventanas entre divulgación y explotación se van a seguir acortando, y las ramas sin soporte serán las primeras en caer. Si tienes sistemas en PHP 8.1 o anterior, o en 8.2, que pierde soporte el 31 de diciembre, planea ya la migración a 8.4. Es el mismo tipo de trabajo que hacemos con agentes de código como Claude Code para acelerar migraciones y auditorías.

Apoyo de Aldama

Si tienes muchos sitios o servidores y necesitas manos: inventario de versiones y SAPIs, parcheo coordinado con tu hosting, revisión de señales de compromiso, rotación de secretos y migración de PHP 7.x u 8.1 a 8.4 con pruebas de compatibilidad. Escríbenos por WhatsApp o mira nuestro servicio de desarrollo de software a la medida.

Fuentes

Actualizado el 21 de octubre de 2026. Actualizaremos esta guía con IoC confirmados y nuevas variantes.

Preguntas frecuentes

¿Qué versiones de PHP corrigen CVE-2026-109618 y CVE-2026-109619?

PHP 8.5.12, 8.4.27, 8.3.36 y 8.2.35, publicadas el 21 de octubre de 2026. PHP 8.6.0 RC4 también incluye las correcciones. Para 7.4, 8.0 y 8.1 solo hay backports mínimos en código fuente o parches de distribuciones y vendors LTS.

¿Afecta a PHP-FPM con nginx o solo a mod_php?

Afecta a todas las instalaciones que atienden peticiones web: PHP-FPM, Apache con mod_php, php-cgi, FrankenPHP y LiteSpeed. mod_php es el caso de mayor riesgo porque el exploit puede dispararse antes de que se ejecute código de la aplicación.

¿php -v me confirma que estoy parchado?

No siempre. El binario CLI puede ser distinto del que atiende la web, y Debian, Ubuntu y RHEL aplican backports sin cambiar la versión upstream. Verifica el changelog del paquete buscando los CVE, por ejemplo con apt-get changelog o rpm -q --changelog.

¿Sirve desactivar session.upload_progress.enabled?

Reduce la exposición a rutas conocidas de CVE-2026-109619 pero no a todas sus variantes, y no cubre CVE-2026-109618. Debe aplicarse en php.ini, el pool de FPM o la configuración del servidor, nunca con ini_set() o .user.ini. Solo la actualización es una solución completa.

¿Hay explotación activa de PHP2Shell?

Cloudflare y watchTowr reportan intentos de explotación desde el 21 de octubre y Patchstack reporta incidentes comunicados por hostings. Huntress no había observado explotación en su base al cierre del día. La PHP Foundation indicó que las pruebas de concepto filtradas no eran funcionales al momento del release.

¿Debo rotar credenciales después de parchar?

Es recomendable en servidores expuestos sin parche desde el 20 de octubre. Una de las fallas permite divulgar memoria del proceso, donde viven contraseñas de base de datos, salts y llaves de API, sin dejar rastro de ejecución de código.

Apoyo técnico

¿Muchos servidores y poco tiempo? Te ayudamos a parchar

Inventario de versiones y SAPIs, parcheo coordinado, revisión de compromiso, rotación de secretos y migración a PHP 8.4.

Hablar por WhatsApp
CVE-2026-109618CVE-2026-109619PHP2Shellvulnerabilidad PHP RCEparche PHP 8.4.27session.upload_progress.enabledPHP-FPM mod_php vulnerabilidad