Ayer por la mañana mi plan era ridículamente idílico: servirme un café con leche, sentarme en la cueva, terminar de perfilar una módulo infame en Magento 2 y vivir en paz.
(Ja. Iluso de mí).
Aún no le había dado el segundo sorbo a la taza cuando la habitual ruta de revisar email, notificaciones de Slack, Telegram, Whatsapp y las otras 10 vías de comunicación que tenemos los freelance revelaron que algo no iba bien. Correo de alerta del INCIBE, grupos ardiendo y al poco tiempo clientes llamando en modo ataque de pánico: «¡Dani, que hay un agujero del 15 en PHP! ¡Que nos van a hackear la tienda, los pedidos y hasta la máquina del café!».
El monstruo del día tenía nombre de película mala de hackers de los noventa: PHP2Shell (CVE-2026-109618 y CVE-2026-109619). Un supuesto RCE crítico que amenazaba con reventar el planeta y que provocó que hasta el parlamento neerlandés desconectara portales web como quien tira del enchufe de la lavadora porque huele a quemado.
¿El resultado real tras 24 horas bajando al fango de la terminal? Mucho humo de consultora, menos drama técnico del anunciado y otra taquicardia más…
Vamos a destripar qué pasó realmente, cómo funciona la trastienda de este bicho y cómo dejar tus máquinas blindadas sin perder la cabeza.
💀 ¿Qué demonios es PHP2Shell?
Para entender semejante circo hay que meter el hocico en las tripas del motor de PHP (sí, ese código en C que nadie se acuerda que existe).
El drama viene por cómo gestiona las subidas de archivos cuando tienes activa la directiva
session.upload_progress. Una característica pensada con toda la buena fe del mundo para pintarle al usuario una barrita de progreso mientras sube un archivo tocho y evitar que le dé siete veces a F5 pensando que la web ha cascado. Tierno, ¿verdad?El chiste está en que el callback encargado de esta movida (
php_session_rfc1867_callback) se ejecuta demasiado pronto. Se cuela en la fiesta antes de que PHP termine de desperezarse, inicialice sus módulos y limpie la basura de las variables globales. Vamos, que los que picaron esto tenían más prisa por decirle al impaciente usuario que la subida va por el 0% que por barrer la cocina antes de ponerse a cocinar. (¿Qué podría salir mal? SPOILER: Absolutamente todo).Si un atacante manda una petición retorcida diseñada para que PHP reviente su límite de memoria (
memory_limit) justo en esa fase embrionaria, el motor entra en pánico y hace un salto abrupto (bailout / longjmp). Se salta parte de la inicialización, no limpia el puntero a memoria y sigue adelante (a veces).
🕵️♂️ Del RCE Apocalíptico a la Realidad en el Barro
Los primeros titulares gritaban: «¡CVSS 9.2! ¡Ejecución remota de código! ¡Apaguen las luces y corran a los búnkeres!».
Pero cuando los investigadores independientes (gente maja como Jackalsyn o @ArchKnight23) metieron AddressSanitizer (ASAN) y se pusieron a mirar, la película de terror se convirtió más en un enredo:
- La supuesta ejecución remota (Bug S) estaba muerta antes de nacer. No hay forma de poner datos útiles donde apunta ese puntero perdido.
- Lo que queda es un Use-After-Free (UAF): Hay corrupción de memoria, sí. ¿Puede tirar un proceso? Sí. ¿Te van a colar un script espía para robarte la base de datos de clientes? En el 99% de las arquitecturas serias, no.
- Tu arquitectura te salva la vida (si no vives en 2008): Para que el puntero huérfano de la memoria liberada pueda ser reutilizado por la siguiente petición, el proceso worker tiene que sobrevivir al error fatal. Eso pasaba en el pleistoceno con Apache
mod_phpsobrempm_prefork.
Si estás usando un stack moderno para e-commerce —es decir, Nginx o Apache con PHP-FPM (por ejemplo)—, cuando un worker sufre un error fatal por agotamiento de memoria, el pool lo liquida y levanta uno completamente limpio. Fin del vector. El puntero huérfano muere con el proceso.
(Moraleja: si todavía tienes un servidor en producción corriendo mod_php de Apache en pleno 2026, el menor de tus problemas era este CVE; tu verdadero problema es el síndrome de Diógenes tecnológico).
🛠️ La Solución: Cirugía Rápida y a Dormir Tranquilos
Que el apocalipsis se haya quedado en una simple denegación de servicio (DoS) local no significa que nos vayamos a cruzar de brazos. En producción no se dejan agujeros abiertos.
Aquí tienes el plan de acción exacto que ejecuté ayer en mis servidores:
Paso 1: El parche temporal inmediato (Stopgap en 30 segundos)
Si por la razón que sea no puedes actualizar paquetes en este instante (porque dependes de ventanas de mantenimiento, clientes miedosos o aprobaciones burocráticas), corta el problema de raíz apagando el seguimiento de subidas.
Abre tu configuración de PHP o el pool de FPM y desactiva esta opción
session.upload_progress.enabled = Off
Con esa sola línea, el callback maldito no se ejecuta jamás. Guardar, recargar y respirar.
Paso 2: La solución de verdad (Actualizar binarios)
El equipo de PHP reaccionó bastante rápido y soltó las versiones parcheadas para todas las ramas mantenidas:
- PHP 8.5 ➔
8.5.12 - PHP 8.4 ➔
8.4.27 - PHP 8.3 ➔
8.3.36 - PHP 8.2 ➔
8.2.35
En Debian / Ubuntu con los repositorios de Ondřej Surý (el patrón de todos nosotros), esto es tan simple como ejecutar un par de comandos:
sudo apt update
sudo apt --only-upgrade install php8.3-fpm php8.3-cli php8.3-common
(Cambia 8.3 por la versión que corra tu tienda o aplicación).
Paso 3: Ojo no te quedes a medias
No sería la primera vez que veo a alguien jurar que está parcheado mientras sus workers en memoria llevan 45 días sin reiniciarse. Fuerza el reinicio del servicio para purgar la memoria:
# Para PHP-FPM (según tu versión)
sudo systemctl restart php8.3-fpm
# Si estás en Apache
sudo systemctl restart apache2
Verifica que el binario activo canta la versión correcta:
php -v
Si ves el número parcheado en la salida del comando, estás limpio.
Ayer fue otro de esos días que te recuerdan por qué nos gusta este oficio: mañanas de infarto por alertas que prometen el fin del mundo, horas analizando trazas de bajo nivel, y la satisfacción de ver cómo una arquitectura bien montada desde el principio (PHP-FPM, aislamiento de procesos, configuración limpia) te salva el pellejo antes de que el parche oficial llegue a los repositorios.
No te dejes llevar por el pánico de LinkedIn ni por los informes de seguridad inflados para vender auditorías. Parchea tus máquinas, apaga lo que no uses, tómate otro café… ¡y que el Garbage Collector te acompañe! 🤘🔥

Hey! Qué opinas sobre el artículo?