Dos fallos críticos en PHP: qué pasó y qué hacer hoy

El 21 de octubre PHP publicó de urgencia cuatro versiones que corrigen dos vulnerabilidades del intérprete. Permiten ejecutar código en el servidor sin usuario ni contraseña, afectan a todo PHP desde la 5.4 y ya hay sondeos en curso. Esto es lo que hay que saber, en el orden en que hay que actuar.

21 de octubre de 2026 Lectura de 7 minutos CVE-2026-109618 CVE-2026-109619 CVSS 9.2

Si solo vas a leer un párrafo: actualizá PHP a 8.5.12, 8.4.27, 8.3.36 u 8.2.35 y reiniciá todos los workers. Si estás en 8.1 o anterior, no hay versión nueva para vos: dependés del paquete de tu distribución o de migrar. Mientras tanto, desactivá session.upload_progress en el php.ini. Un WAF no alcanza.

Qué pasó

El lunes 20 el equipo de seguridad de PHP avisó que al día siguiente, a las 14:00 UTC, saldría una versión de seguridad para dos fallos críticos, sin dar detalles. La divulgación coordinada estaba prevista para el jueves 22, pero los detalles se filtraron antes de tiempo y el embargo se vino abajo: el parche salió el martes 21 a las 13:52 UTC, unos minutos antes de lo anunciado.

Los fallos los encontró Wiz Research, que les puso el apodo php2shell. Los dos llevan CVSS 9.2 en la escala v4.0 y el mismo impacto: ejecución remota de código sin autenticación y lectura de la memoria del proceso, donde viven contraseñas de base de datos, tokens y claves de API. Wiz demostró el ataque contra las imágenes oficiales más recientes de WordPress, Drupal y Joomla, y aclaró que ni hace falta una aplicación: un Hello World sobre una versión vulnerable alcanza.

Antes de que saliera el parche, varios servicios públicos europeos y japoneses prefirieron apagarse. A la mañana del 21, Cloudflare reportaba los primeros ataques y hostings asociados a Patchstack informaban incidentes; al mediodía la telemetría mostraba sobre todo sondeos, sin evidencia firme de intrusiones. Eso va a cambiar: el código de explotación circula y la ventana de exposición es de cientos de miles de servidores.

Qué son, sin entrar al código

No es un error de una aplicación ni de una biblioteca. Está en el núcleo del intérprete, en cómo PHP arma y desarma el estado interno de cada petición HTTP.

CVE-2026-109618 · corrupción al quedarse sin memoria

Si una petición hace que PHP se quede sin memoria en el momento justo, la inicialización de los datos internos de esa petición se interrumpe a medias. La limpieza que viene después trata esos datos incompletos como si fueran válidos, y a partir de ahí la memoria del proceso queda a disposición del atacante. El detonante es una petición que cualquiera puede mandar, con el tamaño justo.

CVE-2026-109619 · estado que sobrevive entre peticiones

Parte del estado que pertenece a una petición puede quedar vivo después de que su memoria fue liberada. La petición siguiente que atiende el mismo worker puede usar ese estado viejo antes de que la inicialización normal lo pise. Es la clase de fallo que se conoce como use-after-free, y el camino confirmado pasa por el seguimiento de progreso de subidas de archivos de las sesiones (session.upload_progress), activo por defecto desde PHP 5.4.

PHP considera que el riesgo es mayor con Apache y mod_php, donde una petición sin autenticar dispara el ataque antes de que se ejecute una sola línea de la aplicación. Pero PHP-FPM, php-cgi, FrankenPHP y LiteSpeed también están alcanzados: toda instalación que sirva peticiones web.

A quién le toca

  • A todo PHP desde la 5.4 hasta la 8.5.11: al menos uno de los dos fallos está en cada versión intermedia.
  • A cualquier aplicación que corra encima, con o sin fallos propios: WordPress, Drupal, Joomla, Laravel, Symfony, Moodle, un panel hecho a mano.
  • A las imágenes de contenedor que construís vos: no se actualizan solas. Hay que reconstruirlas con un PHP corregido y volver a desplegarlas.
  • A los paneles de hosting compartido: el PHP lo elige el proveedor; conviene preguntarle hoy qué versión sirve y cuándo la cambia.

Qué hacer, en orden

1. Actualizar

Es la única corrección completa. Estas son las versiones publicadas el 21 de octubre, por rama:

RamaVersión corregidaSoporte
PHP 8.58.5.12Activo
PHP 8.48.4.27Activo
PHP 8.38.3.36Solo seguridad
PHP 8.28.2.35Solo seguridad; termina el 31 de diciembre de 2026
PHP 8.1, 8.0, 7.4 y anteriores—Fin de vida: el proyecto no publica versión

Después de instalar, reiniciar todos los workers (el servicio de PHP-FPM, o Apache entero si usás mod_php). Un worker viejo que sigue vivo sigue siendo vulnerable. Las distribuciones y los proveedores de soporte extendido recibieron los parches con antelación; el repositorio de Remi para RHEL y derivados avisó que no tendría paquetes el mismo día.

2. Si estás en una versión sin soporte

Una parte enorme del parque corre PHP 7.4, 8.0 u 8.1, y para esas ramas no hay versión oficial. Las salidas, de mejor a peor:

  1. El paquete de tu distribución. Debian, Ubuntu y RHEL retroportan correcciones a las versiones que empaquetan; mirá si ya hay actualización y aplicala.
  2. Si compilás desde el código fuente, el equipo de seguridad de PHP dejó ramas en GitHub con el parche mínimo para 7.4, 8.0 y 8.1 (PHP-7.4-CVE-2026-109618-109619 y equivalentes). No son versiones publicadas: son un favor, sin pruebas completas.
  3. Migrar a 8.2 o superior. Es lo que había que hacer de todas formas, y hoy dejó de ser postergable.

3. Mientras tanto: mitigaciones

Reducen la superficie pero no dejan la instalación segura, en palabras del propio proyecto. Sirven para las horas o los días que tarde la actualización, no para reemplazarla. Van en el php.ini, en el pool de FPM o en la configuración del servidor, nunca con ini_set() ni en un .user.ini, porque tienen que aplicarse antes de que PHP empiece a leer la petición. Y después de cambiarlas, reiniciar los workers.

; Contra CVE-2026-109619: corta el camino confirmado por sesiones
session.upload_progress.enabled = 0

; Solo en PHP 8.5: corta el camino por el backtrace de errores fatales
fatal_error_backtraces = 0

; Contra CVE-2026-109618: en el pool de FPM, para que la app no lo pise
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M        ; 32M si la app necesita subir archivos
php_admin_value[upload_max_filesize] = 8M  ; siempre menor que post_max_size

La idea detrás de memory_limit = -1 es contraintuitiva: el fallo se dispara cuando PHP falla al pedir memoria, así que se le saca el límite propio y se pone el tope en otro lado, con un cgroup o el límite del contenedor, que mata el proceso en vez de dejarlo a medio inicializar. No usar RLIMIT_AS ni RLIMIT_DATA para eso: provocan justamente el fallo de asignación que se quiere evitar.

Dos cosas más que recomienda PHP y que suelen pasarse por alto: sacar de la configuración por petición las directivas inválidas u obsoletas que emiten avisos antes de la inicialización (esconderlos con error_reporting, display_errors o @ no ayuda), y arreglar los errores fatales y los tiempos de espera que un atacante pueda provocar desde afuera: subidas, importaciones, callbacks.

4. Lo que no alcanza

  • Un WAF. Cloudflare publicó reglas el mismo día y sirven como parche provisorio, pero solo si el servidor acepta tráfico exclusivamente desde el WAF. Si tu origen responde directo a internet, el atacante lo esquiva.
  • Parches sueltos copiados de un foro. Hubo mucha circulación de fragmentos sin verificar en las horas previas. El parche es el del proyecto, nada más.
  • Actualizar la aplicación. WordPress 6.x al día sobre PHP 8.1 sigue siendo vulnerable: el problema está debajo.

Cómo saber si te tocaron

Antes de dar por cerrado el tema conviene mirar los registros de los últimos días. Las señales que están reportando los equipos de respuesta:

  • Peticiones multipart/form-data inusuales, seguidas de errores de límite de memoria o de respuestas 500 repetidas.
  • Cookies PHPSESSID anormalmente largas o malformadas.
  • Reinicios de workers de PHP que no se explican por la carga.
  • Archivos nuevos o modificados fuera de cualquier despliegue: en el directorio de subidas, en la raíz, con nombres que imitan a los del núcleo.

Si ves alguna de estas señales, el orden es: actualizar, tratar el servidor como potencialmente comprometido y rotar las credenciales que ese servidor tenía en memoria o en disco: la de la base de datos, las claves de API, los secretos de sesión.

Lo que esto deja en evidencia

Hoy la pregunta que más se repitió en los equipos no fue «¿cómo actualizo?» sino «¿qué versión de PHP está corriendo cada uno de nuestros sitios?». Quien tenía un inventario respondió en diez minutos y actualizó a la tarde. Quien no, pasó el día entrando por SSH a servidores uno por uno, y todavía no sabe si le quedó alguno.

Un fallo de esta escala no se repite todos los meses, pero tampoco es el último. Lo que cambia el resultado no es la velocidad de reacción el día del parche; es saber de antemano qué hay instalado, qué versión, y qué cambió en cada sitio sin que nadie lo pidiera. De eso hablo en cómo trabajo sobre sitios y flotas web, y es lo primero que mira una auditoría técnica.

Fuentes