Saltar al contenido

Seguridad

PHP2Shell (CVE-2026-109618, CVE-2026-109619): qué actualizar, qué revisar y cómo ayuda un WAF

Dos fallos críticos de PHP permiten ejecutar código en remoto sin autenticación. Actualiza a 8.5.12, 8.4.27, 8.3.36 u 8.2.35, desactiva el progreso de subida de sesión y revisa los registros en busca de las señales que explicamos aquí.

Por el equipo de seguridad de OpenWAF

13 min de lectura

Compartir
El elefante de PHP2Shell alcanzado por un rayo, junto a una señal de aviso
Ilustración: PHP2Shell / Wiz (php2shell.com)

En resumen. PHP2Shell es el nombre que los investigadores dieron a dos fallos críticos del motor de PHP, CVE-2026-109618 y CVE-2026-109619 (puntuación CVSS 4.0 de 9,2), publicados el 21 de octubre de 2026. Los dos pueden acabar en ejecución remota de código sin autenticación (RCE en PHP) con el usuario de PHP del servidor web. Están corregidos en PHP 8.5.12, 8.4.27, 8.3.36 y 8.2.35.

  • Actualiza PHP ya y reinicia todos los procesos de PHP. Ningún cambio de configuración lo corrige del todo.
  • Mientras tanto, pon session.upload_progress.enabled=0 en php.ini o en la configuración del pool, y baja post_max_size.
  • Un tercer fallo, CVE-2026-115560, no está corregido en esas versiones. El mismo ajuste lo cubre hasta la próxima versión de mantenimiento de PHP.
  • OpenWAF bloquea en el borde las peticiones que llevan el campo del progreso de subida de sesión (regla 10075). Es una medida provisional y no sustituye a la actualización.

Qué es PHP2Shell

PHP2Shell es una familia de fallos de seguridad de memoria en la forma en que PHP prepara y cierra cada petición web. La descubrieron investigadores de Wiz, Calif y Codex Security de OpenAI, que señalan que el código afectado se remonta a PHP 5.4. El proyecto PHP publicó dos avisos el 21 de octubre de 2026 y, a la vez, versiones nuevas de todas las ramas con soporte.

CVEAvisoQué fallaImpacto
CVE-2026-109618GHSA-w8hw-w9fx-j79w
«RCE via OOM corruption»
Un error por falta de memoria puede interrumpir PHP cuando los datos de la petición solo están inicializados en parte. La limpieza de la petición trata después esos datos inválidos como válidos.RCE sin autenticación. Validada por HTTP contra mod_php con los límites de memoria y de entrada por defecto.
CVE-2026-109619GHSA-6wmf-4rv5-p3rp
«RCE via stale global state»
Un estado que pertenece a la petición puede sobrevivir a la memoria que lo respalda. La siguiente petición que atiende el mismo proceso puede usarlo antes de que se reinicie (un uso tras liberación).RCE sin autenticación y fuga de memoria de otras peticiones.

Los dos avisos tienen el mismo vector CVSS 4.0, AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H: accesible por la red, sin inicio de sesión, sin interacción del usuario y con impacto total en el servidor. La complejidad del ataque figura como alta, pero los investigadores demostraron exploits funcionales, así que no conviene fiarse de esa nota.

Cómo llega un atacante a los fallos

En CVE-2026-109618, el atacante provoca un error por falta de memoria en el peor momento. El aviso describe varias formas de hacerlo a través del analizador multipart:

  • un cuerpo sin un Content-Length utilizable se salta la comprobación de post_max_size;
  • cada parte multipart puede llevar cualquier número de cabeceras;
  • los campos de fichero vacíos no cuentan para max_file_uploads, pero generan metadatos igualmente, y los nombres de campo anidados multiplican el trabajo.

En CVE-2026-109619, una petición deja un estado obsoleto y otra posterior en el mismo proceso lo consume. Las vías confirmadas son:

  • el progreso de subida de sesión, activado por defecto y que funciona sin que la aplicación llame nunca a session_start();
  • los avisos que generan los ajustes INI por petición (php_value en .htaccess, o PHP_VALUE en FPM);
  • el ajuste fatal_error_backtraces de PHP 8.5.

A quién afecta

Según el proyecto PHP, corre riesgo cualquier instalación de PHP que atienda peticiones web. La interfaz (SAPI) con la que se ejecuta PHP cambia lo fácil que es el ataque:

SAPIRiesgoPor qué
Apache mod_phpEl más altomod_php ejecuta siempre el cierre de la petición, aunque el arranque haya fallado. El exploit demostrado se dispara antes de que se ejecute el código de la aplicación, así que da igual qué aplicación haya encima.
PHP-FPM (Nginx, proxy_fcgi de Apache, Caddy)AltoFPM termina el proceso hijo cuando falla el arranque, y no se ha mostrado un exploit completo de CVE-2026-109618 en FPM. La RCE por CVE-2026-109619 sí se validó en FPM con una operación adecuada de la aplicación.
php-cgiAfectadoEl proyecto PHP lo incluye entre las SAPI web afectadas.
FrankenPHPAltoProcesos de larga duración. El aviso lo considera probablemente vulnerable a ataques que no dependen de la aplicación.
LiteSpeed (LSAPI)AfectadoSe consideran probables los exploits que dependen de la aplicación, pero no se han validado.

Las webs con WordPress, Drupal o Joomla funcionan sobre estas mismas SAPI. Los investigadores informan de RCE previa a la autenticación en las tres, y la fuga de memoria de CVE-2026-109619 funciona sea cual sea la aplicación.

Versiones corregidas

RamaCorregido enNotas
PHP 8.58.5.12Si aún no puedes actualizar, pon también fatal_error_backtraces=0.
PHP 8.48.4.27
PHP 8.38.3.36
PHP 8.28.2.35El soporte de seguridad termina el 31 de diciembre de 2026.
PHP 8.1, 8.0, 7.4Sin versiónSin soporte. El equipo de seguridad de PHP publicó parches mínimos en código fuente como ramas: 8.1, 8.0 y 7.4.

La versión candidata de PHP 8.6.0 publicada ese mismo día (RC4) también incluye las correcciones.

Paquetes de las distribuciones. Las distribuciones de Linux y los proveedores de soporte extendido recibieron los parches por adelantado. Un paquete puede llevar la corrección con un número de versión que parece antiguo, así que busca los CVE en su registro de cambios en lugar de comparar versiones. Por ejemplo:

apt changelog php8.2-fpm | grep -E 'CVE-2026-10961[89]'   # Debian, Ubuntu
rpm -q --changelog php-fpm | grep -E 'CVE-2026-10961[89]'  # RHEL, Alma, Rocky
php -v                                                     # solo compilaciones oficiales

Después de actualizar, reinicia todos los procesos de PHP: Apache si usas mod_php, cada pool de FPM y los procesos de FrankenPHP y LiteSpeed. Un proceso que sigue en marcha mantiene el código vulnerable en memoria.

Estado de la explotación

La publicación fue precipitada. La tarde antes de la fecha prevista se publicó por error un vídeo con una prueba de concepto, y The Hacker News informó de los primeros ataques y de «intentos de explotación activos» el 21 de octubre, el mismo día de los parches. Informaciones posteriores hablan de intentos registrados en honeypots desde el 17 de octubre y de variantes de la botnet Mirai que ya prueban los fallos. Por ahora ninguna fuente ha confirmado públicamente una intrusión con éxito. Con tanto escaneo, da por hecho que cualquier servidor PHP sin parchear recibirá intentos.

Mitigaciones parciales y sus límites

El proyecto PHP lo deja claro: solo actualizar es una solución completa. Las medidas siguientes reducen la exposición a vías de ataque concretas mientras programas la actualización. No hacen segura una instalación.

Para CVE-2026-109618 (corrupción por falta de memoria)

  • memory_limit=-1, fijado donde las aplicaciones no puedan cambiarlo (php_admin_value en el pool de FPM o en la configuración de Apache). Así desaparece el fallo por límite de memoria de PHP que controla el atacante. Un fallo de asignación del sistema operativo todavía puede llegar al código vulnerable.
  • Un post_max_size bajo: 8M en webs sin subidas de ficheros y 32M si las necesitas, con upload_max_filesize por debajo.
  • Límites de petición en el servidor web o en el proxy para el tamaño del cuerpo decodificado, el número de campos, de partes multipart y de cabeceras, y la profundidad de anidamiento. Tienen que cubrir también las peticiones sin un Content-Length utilizable.
  • Un límite de memoria del contenedor o del cgroup como frontera de disponibilidad, a ser posible uno que mate solo el proceso afectado. No uses RLIMIT_AS ni RLIMIT_DATA: pueden provocar justo el fallo de asignación que necesita el ataque.

Para CVE-2026-109619 (estado global obsoleto)

  • session.upload_progress.enabled=0 en php.ini, en el pool de FPM o en la configuración del servidor, y después reinicia todos los procesos. ini_set() y el .user.ini de FPM se aplican demasiado tarde y no sirven. Cierra las vías de sesión confirmadas, no todas las variantes.
  • En PHP 8.5, fatal_error_backtraces=0, que solo cierra la vía confirmada de las trazas de errores fatales.
  • Quita los ajustes por petición no válidos u obsoletos que generan avisos antes de que empiece la petición. Ocultarlos con error_reporting, display_errors o @ no sirve.
  • Corrige los errores fatales y los tiempos de ejecución agotados que pueda provocar un atacante, también en callbacks, subidas, importaciones y código de limpieza.
; php.ini o pool de FPM (php_admin_value[...] = ...); después, reinicia todos los procesos
session.upload_progress.enabled = 0
post_max_size = 8M          ; 32M si la web acepta subidas
upload_max_filesize = 4M    ; siempre por debajo de post_max_size
fatal_error_backtraces = 0  ; solo PHP 8.5

Ojo a un cambio de comportamiento tras actualizar. Quedarse sin memoria ya no detiene PHP en el acto: el error salta en el siguiente punto seguro, y un segundo límite, duro y por encima de memory_limit, termina el proceso sin más. En ese caso no se ejecutan las funciones de cierre, así que revisa el código que dependa de register_shutdown_function() para registrar o limpiar tras un error de memoria.

Señales de ataque

Los investigadores citados por The Hacker News señalan estas pistas. Búscalas en los registros del servidor web, de PHP y de FPM desde el 17 de octubre:

  • peticiones multipart/form-data extrañas, a menudo a URL que nunca reciben subidas, seguidas de errores «Allowed memory size exhausted» o de respuestas HTTP 500 repetidas;
  • cookies PHPSESSID anormalmente grandes en las respuestas;
  • procesos de PHP que se reinician o se caen sin motivo claro (child exited on signal en FPM, fallos de segmentación en el registro de errores de Apache);
  • ráfagas de avisos antes de que se ejecute ningún script, avisos de limpieza o «Maximum execution time exceeded» en URL raras, que los avisos GHSA citan como señales que conviene revisar.

Mientras investigas, activa log_errors con error_reporting=E_ALL. Unos registros limpios no prueban nada: un exploit con éxito puede no dejar ningún error de PHP. Si encuentras estas señales en un servidor sin parchear, trátalo como posiblemente comprometido. Busca ficheros nuevos en directorios con permiso de escritura, tareas cron nuevas y conexiones salientes inesperadas del usuario de PHP, y cambia los secretos que pueda leer la aplicación.

La continuación: CVE-2026-115560

El 23 de octubre de 2026, dos días después de los parches, el proyecto PHP publicó un aviso informativo sobre otro vector de RCE, distinto y «poco probable», en el progreso de subida de sesión: CVE-2026-115560. Las versiones del 21 de octubre no lo corrigen.

Necesita una combinación poco habitual de configuración y código:

  • la configuración pone session.serialize_handler en php_binary o php_serialize;
  • la aplicación lo cambia a php en tiempo de ejecución con ini_set() antes de llamar a session_start();
  • el progreso de subida de sesión sigue activado.

Las aplicaciones que nunca cambian el serializador en tiempo de ejecución no están expuestas. El proyecto PHP publicará la corrección y el aviso completo con la próxima versión de mantenimiento; no ha anunciado fecha ni versión. Su consejo es poner session.upload_progress.enabled=0 hasta entonces. Si ya lo hiciste por CVE-2026-109619, mantenlo.

Para comprobar si tu código cambia el serializador:

grep -rnE "ini_set\(\s*['\"]session\.serialize_handler" --include='*.php' .

Cómo protege OpenWAF tus webs

La regla 10075 está activa en el borde de OpenWAF. Bloquea cualquier petición en la que un argumento se llame PHP_SESSION_UPLOAD_PROGRESS (sin distinguir mayúsculas), esté en un cuerpo multipart, en un cuerpo URL-encoded o en la cadena de consulta. Es el campo que lee PHP para empezar el progreso de subida de sesión. Al descartarlo en el borde, esas peticiones no llegan al proceso de PHP, lo que cubre las vías de sesión confirmadas de CVE-2026-109619 y el vector de CVE-2026-115560.

Una regla de WAF es una medida provisional, y esta tiene límites claros:

  • No cubre CVE-2026-109618 en general. Las vías de falta de memoria pasan por el propio analizador multipart, y una petición pensada para ellas no necesita ese campo. Los límites de tamaño y de tiempo de petición de cada web dificultan agotar la memoria, pero no lo corrigen.
  • No cubre las vías de CVE-2026-109619 que dependen de la configuración del servidor, como los avisos INI por petición o fatal_error_backtraces.
  • Solo reconoce el nombre de campo por defecto. Si una aplicación cambió session.upload_progress.name, esta regla no bloquea las peticiones con el nombre nuevo.
  • Solo protege los nombres de host que pasan por OpenWAF. El tráfico que llega directamente a tu origen se la salta, así que limita el origen a OpenWAF siempre que puedas.

Las barras de progreso de subida legítimas usan el mismo campo, así que dejan de funcionar detrás de la regla. Si necesitas una, añade una excepción por web para la regla 10075 en esa ruta, y solo cuando el servidor ya tenga una versión de PHP corregida. Las webs con el WAF en modo solo registro anotan las peticiones que coinciden en lugar de bloquearlas.

La solución sigue siendo actualizar PHP. La regla te da tiempo para hacerlo.

Lista de comprobación

  1. Haz inventario de cada servidor, imagen de contenedor y cuenta de alojamiento con PHP, y anota la SAPI (mod_php, FPM, CGI, FrankenPHP, LiteSpeed).
  2. Actualiza a 8.5.12, 8.4.27, 8.3.36 u 8.2.35, o instala el paquete de tu distribución cuyo registro de cambios cite CVE-2026-109618 y CVE-2026-109619.
  3. En 7.4, 8.0 u 8.1, aplica el parche en código fuente o el paquete de tu proveedor de soporte extendido, y planifica el paso a una rama con soporte.
  4. Reinicia Apache, cada pool de FPM y todos los procesos de PHP de larga duración. Reconstruye y vuelve a desplegar las imágenes de contenedor.
  5. Pon session.upload_progress.enabled=0 en php.ini o en el pool hasta que salga la corrección de CVE-2026-115560, o para siempre si no usas el progreso de subida.
  6. Hasta que todos los servidores estén parcheados, baja post_max_size, aplica límites de petición en el proxy y pon fatal_error_backtraces=0 en PHP 8.5.
  7. Revisa los registros desde el 17 de octubre en busca de las señales anteriores, y trata como posiblemente comprometidos los servidores sin parchear que las muestren.
  8. Pon las webs PHP públicas detrás de un WAF que bloquee PHP_SESSION_UPLOAD_PROGRESS mientras actualizas, y limita los orígenes al WAF.

Preguntas frecuentes

¿Se está explotando PHP2Shell?

Los intentos de explotación empezaron a las pocas horas de la publicación del 21 de octubre de 2026, según The Hacker News, que cita a Cloudflare, watchTowr y otros. Mientras escribimos esto ninguna fuente ha confirmado públicamente una intrusión con éxito, pero con escaneos masivos cualquier servidor PHP sin parchear es un objetivo.

Uso Nginx con PHP-FPM, no mod_php. ¿Me afecta?

Sí. El proyecto PHP incluye todas las instalaciones que sirven peticiones web: PHP-FPM, php-cgi, FrankenPHP y LiteSpeed. mod_php es el caso de mayor riesgo porque hay un exploit demostrado que se dispara antes de que se ejecute el código de la aplicación; en FPM se validó la ejecución remota de código por CVE-2026-109619 con una operación adecuada de la aplicación. Actualiza en cualquier caso.

Mi distribución sigue mostrando una versión antigua de PHP. ¿Soy vulnerable?

No necesariamente. Las distribuciones y los proveedores de soporte extendido recibieron los parches por adelantado y suelen aplicarlos sin cambiar el número de versión original. Busca CVE-2026-109618 y CVE-2026-109619 en el registro de cambios del paquete en vez de comparar números de versión.

¿Basta con session.upload_progress.enabled=0?

No. Corta las vías confirmadas de CVE-2026-109619 a través del progreso de subida de sesión y el vector de CVE-2026-115560, pero no la corrupción por falta de memoria de CVE-2026-109618 ni otras variantes. Solo actualizar PHP corrige PHP2Shell. Si no usas barras de progreso de subida, deja el ajuste desactivado también después de actualizar.

¿Me protege un WAF frente a PHP2Shell?

En parte. Un WAF puede descartar las peticiones que llevan el campo PHP_SESSION_UPLOAD_PROGRESS, como hace la regla 10075 de OpenWAF, y los límites de tamaño de petición dificultan agotar la memoria. No ve todas las vías de CVE-2026-109618 ni las de CVE-2026-109619 que dependen de la configuración. Tómalo como una medida provisional mientras actualizas.

¿Qué es CVE-2026-115560 y tiene parche?

Es un vector distinto y poco probable de ejecución remota de código en el progreso de subida de sesión, anunciado por el proyecto PHP el 23 de octubre de 2026. Necesita una configuración poco habitual: session.serialize_handler con php_binary o php_serialize en la configuración y cambiado a php con ini_set() antes de session_start(). Las versiones del 21 de octubre no lo corrigen; el parche y el aviso completo llegarán con la próxima versión de mantenimiento. Hasta entonces, pon session.upload_progress.enabled=0.

¿Qué hago con PHP 7.4, 8.0 u 8.1?

Esas ramas ya no reciben versiones. El equipo de seguridad de PHP publicó parches mínimos en código fuente para 7.4, 8.0 y 8.1, pensados para quien compila PHP; si no, pregunta a tu proveedor de soporte extendido o a tu distribución, o pasa a una rama con soporte.

Fuentes

Temas

  • PHP2Shell
  • CVE-2026-109618
  • CVE-2026-109619
  • CVE-2026-115560
  • PHP RCE
  • session upload progress
  • mod_php
  • PHP-FPM

Autor

OpenWAF

Sigue leyendo

Ver todo

Trae las webs de tu agencia al acceso anticipado.

OpenWAF es gratis mientras está en acceso anticipado. Crea tu cuenta, añade los dominios de tus clientes y cambia sus servidores de nombres o añade un CNAME: el panel te guía en cada paso.