PHP2Shell en 2026: Cómo Proteger Tu Servidor PHP de las Fallas CVE-2026-109618 y 109619
Hola HaWkers, el 21 de octubre de 2026 el proyecto PHP lanzó una actualización de emergencia: las versiones 8.5.12, 8.4.27, 8.3.36 y 8.2.35 corrigen dos fallas críticas que permiten ejecución remota de código sin autenticación. Ambas recibieron una puntuación de 9.2 en el CVSS y se hicieron conocidas con el apodo de PHP2Shell, porque el objetivo final del ataque es conseguir una shell en el servidor.
El detalle que asusta: las fallas existen desde PHP 5.4, atacan partes del motor que prácticamente toda petición toca (gestión de memoria y manejo de errores) y, en Apache con mod_php, el ataque ocurre antes de que se ejecute cualquier línea de tu código. No importa si tu Laravel está impecable.
¿Sabes ahora mismo, sin abrir la terminal, qué versión de PHP está corriendo en producción? Si la respuesta es "creo que es la 8.2", este artículo es para ti. Al final vas a tener un checklist para actualizar, aplicar mitigaciones mientras no actualizas y buscar señales de que alguien ya intentó entrar.
Qué Es PHP2Shell y Por Qué Es Tan Grave
Son dos vulnerabilidades distintas, publicadas juntas:
- CVE-2026-109618 (RCE por corrupción tras falta de memoria): cuando una petición alcanza el
memory_limiten el momento equivocado, PHP puede dejar datos internos de la petición parcialmente inicializados. Durante la limpieza, el motor trata esa basura como datos válidos y corrompe la memoria. El vector conocido es un nombre de campo de formulario gigante. - CVE-2026-109619 (RCE por estado global "viejo"): un error fatal en el punto equivocado deja estado interno apuntando a memoria de una petición anterior que ya fue liberada. La siguiente petición atendida por el mismo worker usa esa memoria: es el clásico use-after-free. El vector conocido pasa por el callback de
session.upload_progress.
Ninguna de las dos fallas requiere login ni interacción del usuario. La complejidad del ataque se considera alta, pero eso no trae mucho alivio, porque el propio PHP demostró ejecución remota de código en Apache con mod_php usando la configuración por defecto.
Quién corre más riesgo
El impacto depende de cómo se ejecuta PHP (el llamado SAPI):
| Forma de ejecución | Riesgo | Lo que se sabe |
|---|---|---|
| Apache + mod_php | Más alto | RCE demostrado antes de que corra el código de la aplicación |
| PHP-FPM | Alto | RCE confirmado a través de rutas del código de la aplicación |
| php-cgi, FrankenPHP, LiteSpeed | En riesgo | Listados como afectados, sin la misma demostración pública |
En resumen: si tu PHP atiende peticiones HTTP, estás en el grupo afectado.
La Línea de Tiempo: Auditorías, IA y un Embargo Que Se Filtró
La historia de cómo aparecieron estas fallas dice mucho sobre la seguridad del open source en 2026. Según el blog de la PHP Foundation:
- 2024: Quarkslab hace la primera auditoría externa de PHP en años, organizada por OSTIF y financiada por la Sovereign Tech Agency. Al corregir un problema reportado allí, un desarrollador del core encuentra las primeras señales del bug de falta de memoria.
- Mayo de 2026: la fundación crea el Ecosystem Security Team.
- A partir del 1 de julio de 2026: el equipo publica 15 CVEs y procesa más de 100 reportes inválidos, duplicados o no reproducibles.
- 30 de julio de 2026: Calif empieza a auditar PHP dentro del programa Patch the Planet, de OpenAI.
- 11 de agosto de 2026: el investigador Ryan A, de Calif, reporta un RCE incondicional con la misma causa raíz.
- 24 de agosto y 18 de septiembre de 2026: Wiz y OpenAI reportan otros vectores de ataque.
- 20 de octubre de 2026: los IDs de los CVEs se filtran en internet con hora de release y puntuación incorrectas (circuló un 10.0), PHP publica el preanuncio antes de lo previsto y Calif publica sin querer un video de la prueba de concepto.
- 21 de octubre de 2026, 14:00 UTC: release coordinado, adelantado desde el día 22.
Fíjate en dos cosas. Primero, las herramientas de IA están en medio del proceso: Alpha-Omega ejecutó Claude Mythos, de Anthropic, contra el código de PHP, y el equipo empezó a usar Daybreak Red, de OpenAI, para validar reportes. Segundo, el embargo no aguantó. Cuando salió el parche, mucha gente ya sabía exactamente dónde mirar.
Paso 1: Descubre Qué PHP Estás Ejecutando
Parece obvio, pero el PHP de la terminal no siempre es el mismo que atiende el sitio. Un servidor puede tener el CLI en 8.3 y el FPM en 8.2. Revisa los dos:
# Versión de PHP de línea de comandos
php -v
# Versiones de PHP-FPM instaladas (Debian/Ubuntu)
ls /usr/sbin/php-fpm* 2>/dev/null
for bin in /usr/sbin/php-fpm*; do "$bin" -v | head -n 1; done
# Pregúntale al propio servidor web qué PHP responde
# (crea el archivo, accede y BÓRRALO enseguida)
echo '<?php echo PHP_VERSION, " ", PHP_SAPI;' > /var/www/html/versao-tmp.php
curl -s https://seu-dominio.com.br/versao-tmp.php; echo
rm /var/www/html/versao-tmp.phpCon la versión en mano, compárala con la tabla de correcciones:
| Rama | Vulnerable | Corregida |
|---|---|---|
| PHP 8.5 | por debajo de 8.5.12 | 8.5.12 |
| PHP 8.4 | por debajo de 8.4.27 | 8.4.27 |
| PHP 8.3 | por debajo de 8.3.36 | 8.3.36 |
| PHP 8.2 | por debajo de 8.2.35 | 8.2.35 |
¿Y si aparece 8.1, 8.0 o 7.4? Esas ramas ya no reciben actualizaciones del proyecto. El equipo de seguridad publicó backports mínimos en código fuente para 7.4, 8.0 y 8.1, pensados para quien compila PHP por su cuenta, y las distribuciones y proveedores de soporte extendido recibieron los parches antes. Fuera de eso, el camino es migrar. Recuerda también que PHP 8.2 llega al fin de vida el 31 de diciembre de 2026, así que quien esté en esa versión tendrá que moverse de nuevo pronto.
Paso 2: Actualiza (y Reinicia Todos los Workers)
La corrección completa es una sola: actualizar. El resto del artículo es contención. Un script que verifique si la versión en ejecución ya está corregida ayuda mucho en un pipeline de deploy o en un cron de auditoría:
<?php
// checa-php2shell.php - verifica si el PHP en ejecución ya tiene las correcciones de octubre de 2026
$corrigidas = [
'8.5' => '8.5.12',
'8.4' => '8.4.27',
'8.3' => '8.3.36',
'8.2' => '8.2.35',
];
$ramo = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION;
if (!isset($corrigidas[$ramo])) {
// 8.1 o más antiguo: sin release oficial, solo backport o migración
fwrite(STDERR, "PHP {$ramo} está fuera de soporte. Migra o usa un backport de tu proveedor.\n");
exit(2);
}
if (version_compare(PHP_VERSION, $corrigidas[$ramo], '<')) {
fwrite(STDERR, "VULNERABLE: PHP " . PHP_VERSION . " (necesita {$corrigidas[$ramo]} o superior)\n");
exit(1);
}
echo "OK: PHP " . PHP_VERSION . " ya incluye las correcciones de PHP2Shell\n";Ejecútalo con php checa-php2shell.php en cada imagen o servidor. Un código de salida distinto de cero hace fallar el pipeline, que es exactamente lo que quieres.
Una vez actualizado el paquete, reinicia todos los workers. Un FPM que sigue con procesos antiguos en pie continúa ejecutando el binario vulnerable:
# Debian/Ubuntu con PHP-FPM 8.3 (ajusta el número de la rama)
sudo apt update && sudo apt install --only-upgrade php8.3-fpm php8.3-cli
sudo systemctl restart php8.3-fpm
# Apache con mod_php: PHP vive dentro del proceso de Apache
sudo systemctl restart apache2
# Contenedores: reconstruye la imagen a partir de la base nueva, no solo reinicies
docker build --pull -t minha-app:php-corrigido .En contenedores, el --pull importa: sin él, Docker puede reutilizar la imagen base antigua de la caché y terminas publicando el mismo PHP vulnerable con una etiqueta nueva.
Paso 3: Mitigaciones Mientras No Actualizas
A veces no se puede actualizar hoy: hosting compartido, aplicación legacy atada a una versión, ventana de mantenimiento ya programada. php.net enumera mitigaciones, pero deja claro que no hacen segura la instalación, solo reducen la superficie.
Para la CVE-2026-109619, desactiva el progreso de subida por sesión en el php.ini o en el pool de FPM:
; php.ini o pool de FPM - mitigación temporal de PHP2Shell
; Cierra el vector conocido de la CVE-2026-109619 (rompe las barras de progreso de subida)
session.upload_progress.enabled = 0
; Solo en PHP 8.5: desactiva los backtraces en errores fatales
; fatal_error_backtraces = 0
; Mitigación de la CVE-2026-109618: limita el tamaño de los POST
; 8M si la aplicación no recibe subidas, 32M si las recibe
post_max_size = 8M
upload_max_filesize = 6MDetalles que tumban a quien lo hace con prisa:
- No confíes en
ini_set()ni en el.user.inide FPM para esto. La configuración tiene que estar en elphp.ini, en el pool o en la configuración del servidor. - Reinicia todos los workers después del cambio.
- php.net también menciona
memory_limit=-1(preferiblemente víaphp_admin_value) como mitigación de la CVE-2026-109618 y pide no usarRLIMIT_ASniRLIMIT_DATA. Evalúalo con cuidado: sin límite de memoria, un script con una fuga puede tumbar la máquina entera.
Hay un motivo más para desactivar session.upload_progress incluso después de actualizar. El 23 de octubre de 2026, PHP publicó un aviso informativo sobre un tercer problema, la CVE-2026-115560, que no se corrige con los releases del día 21. Solo afecta a aplicaciones que configuran session.serialize_handler como php_binary o php_serialize y lo cambian a php en tiempo de ejecución con ini_set() antes de session_start(). Es un escenario raro, y la corrección llegará en el próximo release regular. La recomendación oficial es mantener session.upload_progress.enabled=0 hasta entonces.
Paso 4: Bloquea en el Borde Lo Que No Usas
Si tu aplicación no recibe formularios multipart/form-data en ciertas rutas, no hay motivo para aceptar ese tipo de cuerpo en ellas. Bloquear en el borde (Nginx, WAF o CDN) corta el vector antes de que la petición llegue a PHP. Un ejemplo en Nginx para una API que solo habla JSON:
# Nginx - rechaza multipart en rutas que solo deberían recibir JSON
location /api/ {
# Limita el tamaño del cuerpo para dificultar nombres de campo gigantes
client_max_body_size 1m;
if ($content_type ~* "multipart/form-data") {
return 415;
}
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}Ya existen reglas de WAF públicas para ModSecurity y Suricata. La recomendación de Abstract Security es activarlas primero en modo log, revisar los falsos positivos y solo después pasar a bloqueo. Una regla de WAF mal calibrada tumba el checkout de un e-commerce un viernes por la noche.
Otro punto: cualquier hallazgo antiguo de local file inclusion del tipo include($_GET['pagina']) que estaba en el backlog como "medio" debe volver a la cola como crítico. Buena parte de las pruebas de concepto que circularon dependen precisamente de un LFI para convertirse en RCE.
Paso 5: Busca Señales de Que Alguien Ya Lo Intentó
Los detalles se filtraron el 20 de octubre, y equipos de seguridad reportaron intentos de ataque ya el día 21. La ventana de investigación debe empezar el día 20, no el día en que actualizaste. Algunas señales que Abstract Security señala como características:
- Errores fatales de PHP que terminan en
in Unknown on line 0en los logs del servidor web. - POST de 1 MB o más hacia endpoints PHP, sobre todo ráfagas de 10 o más desde la misma IP en 10 minutos.
- En Apache, cientos de POST grandes desde la misma IP generando entradas
AH00052, seguidas de una respuesta lenta, lo que sugiere fuerza bruta contra el ASLR. - Procesos
sh -chijos de Apache, de Nginx o de los workers de PHP, ejecutandoid,curlonc.
Una primera pasada rápida por los logs:
# 1. Firma del exploit en los logs de error (desde el 20/10/2026)
sudo grep -h "in Unknown on line 0" /var/log/apache2/error.log* /var/log/php*-fpm.log 2>/dev/null | tail -n 50
# 2. Crashes de procesos hijos de Apache, agrupados por día
sudo zgrep -h "AH00052" /var/log/apache2/error.log* | awk '{print $2, $3, $5}' | sort | uniq -c
# 3. IPs con más POST en el access log (formato combined)
sudo awk '$6 == "\"POST" {print $1}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -n 20
# 4. Archivos nuevos en directorios temporales y en la raíz web desde el 20/10
sudo find /tmp /dev/shm /var/www -newermt "2026-10-20" -type f -name "*.php" 2>/dev/null¿Encontraste algo? Revisa también claves nuevas en authorized_keys, cron jobs que nadie creó y conexiones salientes inesperadas. Si hay una señal concreta de compromiso, tratarlo como incidente (aislar, preservar evidencia, rotar credenciales) es más seguro que solo actualizar y seguir con la vida.
Lo Que Este Caso Enseña Sobre Seguridad en 2026
Quien siguió React2Shell, la vulnerabilidad crítica en los React Server Components, reconoce el patrón: una falla en el propio runtime o framework, que ninguna revisión de código de tu aplicación habría detectado, y una carrera entre el parche y el primer exploit funcional.
Tres lecciones prácticas:
- El inventario de versiones es seguridad. El primer paso de todo incidente de este tipo es responder "dónde corre qué". Si eso te lleva un día, ya perdiste el día más importante.
- El embargo no es garantía. Esta vez la filtración adelantó el release casi un día. Ten un proceso de actualización que funcione en horas, no en semanas.
- La IA cambió el volumen en ambos lados. El mismo tipo de herramienta que ayudó a encontrar estas fallas también genera reportes falsos (el equipo de PHP descartó más de 100) y acelera a quien busca brechas.
Vale una aclaración honesta: el investigador Elias Taylor argumentó que muchas pruebas de concepto que circularon el día del anuncio eran falsas o solo funcionaban en laboratorio con un componente vulnerable añadido. Eso no cambia su propia conclusión: actualiza de todas formas.
Perspectivas: Lo Que Viene en PHP
PHP 8.6.0 ya está en RC4, y la PHP Foundation reforzó el equipo con Volker Dusch como ingeniero de seguridad de IA residente y Daniel Scherzer enfocado en hardening, además de builds con sanitizers en todas las plataformas soportadas. La fundación también pidió que empresas, hostings, distribuciones y gobiernos que dependen de PHP financien el trabajo en la medida de esa dependencia. El trabajo a tiempo completo que corrigió el bug de memoria fue pagado con patrocinio.
Para quien administra servidores, la agenda de los próximos días es corta: actualizar a 8.5.12, 8.4.27, 8.3.36 u 8.2.35, reiniciar los workers, mantener session.upload_progress.enabled=0 hasta el próximo release regular y revisar los logs desde el 20 de octubre. Y si todavía estás en 8.2, marca ya la migración en el calendario: el fin de vida es el 31 de diciembre de 2026.
¡Vamos con todo! 🦅
📚 ¿Quieres Seguir lo Que Viene Por Delante?
Este artículo cubrió PHP2Shell y cómo proteger servidores PHP de las fallas CVE-2026-109618 y CVE-2026-109619, pero el ecosistema cambia cada semana y no todo se convierte en artículo aquí.
En X comparto lo que estoy probando, los bastidores de los proyectos y las novedades que aparecen antes de convertirse en post.
Sígueme Allá
💡 Contenido diario sobre desarrollo, carrera y las herramientas que realmente uso

