La semana en que crujió el stack: PHP2Shell y tres RCE críticos en PHP, Node.js y Next.js
En siete días de octubre de 2026 cayeron tres vulnerabilidades críticas de ejecución remota de código, una por cada capa del stack web: Next.js (CVE-2026-96889, CVSS 9.5, RCE vía la librería de imágenes sharp), PHP2Shell (CVE-2026-109618/109619, CVSS 9.2, use-after-free en el intérprete que afecta a PHP 5.4 → 8.5 y a casi toda la web) y Node.js (CVE-2026-111497, CVSS 9.8, escritura fuera de límites en el decodificador Brotli). El protagonista es PHP2Shell: te explico en cristiano qué es, cómo funciona la cadena de ataque (reciclar el worker, filtrar memoria por la cookie PHPSESSID para derrotar ASLR, abusar de session.upload_progress), por qué la mayoría de servidores NO es explotable por los exploits públicos, y cómo blindar tu sitio con un laboratorio en Docker y defensa en profundidad. Pero las tres comparten ADN —fallos de memoria en código nativo— y la misma cura: actualizar.
Hay semanas en las que el oficio se para en seco. Esta fue una. El 20 de octubre de 2026, el equipo de PHP publicó dos vulnerabilidades en el núcleo del lenguaje —ojo: no en un framework, no en un plugin, en el intérprete mismo— y la comunidad de seguridad las bautizó con un nombre que lo resume todo: PHP2Shell. De «PHP» a «shell» en un par de peticiones. Cada una con su CVE (CVE-2026-109618 y CVE-2026-109619) y un CVSS de 9.2; la gente de watchTowr incluso le puso un 10.0 redondo a la cadena completa.
Pero lo que de verdad quita el sueño no es la nota, es el alcance. Afectan a PHP 5.4 y a todo lo que vino después. Trece años de versiones. Y como PHP mueve cerca del 70 % de la web —WordPress, Drupal, la mismísima MediaWiki de Wikipedia—, el radio de impacto es, sin exagerar, casi todo lo que visitas a diario. En cuestión de horas ya había sondeos masivos y botnets de la familia Mirai peinando Internet en busca de blancos.
Déjame hacer tres cosas contigo, por orden. Primero, contarte qué son estas dos vulnerabilidades sin que te haga falta un doctorado en gestión de memoria. Segundo, enseñarte cómo luce el ataque —con un laboratorio en Docker que puedes montar en tu máquina—. Y tercero, lo único que de verdad importa cuando cierras la pestaña: cómo blindar tu sitio. Te adelanto el final, porque no es un spoiler que valga la pena guardar: hay una sola cura de verdad, y no es ningún truco de .ini.
Y una cosa más, porque conviene que la tengas en la cabeza desde ya: PHP2Shell no vino solo. Esa misma semana se llevó por delante también a Next.js y a Node.js, cada uno con su propio RCE crítico. Lo veremos al final, porque los tres cuentan, juntos, una historia más interesante que cualquiera por separado. Pero empecemos por el que trae demo.
Antes de seguir: esto es material defensivo
Todo lo que hay aquí —el laboratorio incluido— está pensado para que protejas lo tuyo. No vas a encontrar exploits, ni payloads de RCE, ni web shells. El laboratorio levanta contenedores en tu máquina para que veas la superficie de ataque y aprendas a cerrarla, nada más. Apuntarlo contra sistemas ajenos no solo es ilegal: es justo lo contrario de lo que defiende este artículo.
El detalle que marca época: las encontró una IA
Merece la pena pararse aquí un momento, porque dice bastante de hacia dónde va esto. A estas vulnerabilidades no las encontró un humano peinando código a mano durante meses. Las sacó Wiz Research con ayuda de modelos de IA de frontera. Según la propia divulgación, modelos como Gemini 4 y GPT-5.6-Sol aportaron «de forma significativa» tanto al desarrollo del exploit como a la validación del parche, desenredando cadenas de explotación que a un analista le habrían costado semanas.
Por qué esto importa más allá del titular
Que una IA encuentre y encadene un use-after-free en el intérprete de PHP es una señal de doble filo. El lado bueno: quienes defendemos tenemos ahora una herramienta brutal para auditar código que llevaba décadas sin que nadie lo mirara de cerca. El lado incómodo: quienes atacan tienen exactamente la misma herramienta. La ventana entre «se descubre» y «se explota en masa» se mide ya en horas, no en meses. Parchear rápido dejó de ser una buena costumbre para volverse una carrera.
Qué es PHP2Shell, en cristiano
Las dos CVE son, en el fondo, errores de memoria del tipo use-after-free —usar memoria después de haberla liberado—. Y comparten el mismo detonante: un error fatal a media petición. Lo típico es quedarse sin memoria cuando la petición cruza el memory_limit, y eso corta el código nativo de PHP antes de que limpie lo que tenía entre manos. Esa memoria a medio soltar es la grieta por la que se cuela todo lo demás.
Sobre esa misma grieta, cada CVE abre una puerta distinta:
El fallo vive en el manejador de progreso de subida (upload-progress), que PHP procesa antes de que corra una sola línea de tu aplicación. En las condiciones justas, ese manejador le puede devolver al cliente memoria liberada de un worker, metida dentro de la cookie de respuesta PHPSESSID.
En cristiano: el atacante recibe, dentro de una cookie, restos de memoria de otras peticiones —credenciales, claves, tokens—. Y, tirando del hilo, eso termina en ejecución de código. Es las dos cosas a la vez: una fuga de información y la primera mitad del camino al RCE.
Y aquí está la diferencia que lo cambia todo frente a un fallo de WordPress o de tu propio código: esto vive por debajo de tu aplicación. Da igual lo limpio que tengas el Laravel o lo al día que lleves los plugins. El fallo está en el intérprete que ejecuta todo lo que escribes. Por eso no hay forma de «parchearlo» desde tu código —y por eso la única cura real es cambiar el intérprete, como veremos al final—.
La cadena de ataque, paso a paso
El exploit público que se filtró —su autor lo vende como de un clic, pensado para PHP 8.4.26 sobre Apache con mod_php— trabaja todo por HTTP normal, sin autenticarse ni nada. Y no hay magia negra: son tres movimientos encadenados, cada uno preparando el terreno para el siguiente.
- Reciclar el worker. El atacante provoca a propósito el error fatal por falta de memoria, para dejar atrás ese estado a medio liberar del que hablábamos.
- Derrotar ASLR. Lee las direcciones de memoria que se le filtran dentro de la cookie
PHPSESSID. Con ellas en la mano, anula la aleatorización de direcciones (ASLR), esa defensa que normalmente hace que un exploit de memoria «no sepa» a dónde apuntar. - Ejecutar. Ya con el mapa de memoria, abusa del manejador de session upload progress para colar y correr un comando de shell.
De «PHP» a «shell». Ahí tienes el nombre.
¿Eres un blanco? (spoiler: seguramente no de fábrica)
Aquí toca bajar las pulsaciones y hablar claro, porque los titulares asustan más de lo que la realidad justifica. Ser vulnerable no es lo mismo que ser explotable. Los exploits públicos no funcionan contra una instalación de PHP por defecto: necesitan que tu servidor cumpla varias precondiciones concretas a la vez. Si falta alguna, el atacante se queda en la puerta mirando.
El atacante automatizado no se pone a explotar a lo loco: primero sondea a ver si vale la pena el esfuerzo. Va buscando servidores que delaten estas señales, y necesita varias juntas, no una suelta:
display_errors = On— le regala el estado interno (errores, trazas) que necesita para orientarse.- Una
phpinfo()expuesta — le sirve en bandeja el mapa completo de tu configuración. - Una inclusión de archivos (LFI) en tu app — varias pruebas de concepto la usan como punto de apoyo.
session.use_strict_mode = 0— le deja fijar elPHPSESSIDa su gusto.session.upload_progress.enabled = 1— la vía confirmada del CVE (y, recuerda, viene activa de fábrica).- Un
memory_limitapretado — cuanto más bajo, más fácil le resulta forzar el error fatal por OOM.
Y esto no es teoría optimista mía: lo confirmó el análisis de Sansec. Rastrearon una veintena de sitios públicos y cinco WordPress, y ninguno mostraba errores, exponía phpinfo, tenía un LFI a la vista ni reflejaba la sonda de sesión. No encontraron acceso de shell en ningún sitio a fecha del 22 de octubre. Resumiendo: el cielo no se está cayendo, pero la amenaza es real y oportunista —busca al descuidado—.
El estado real de la explotación, sin alarmismo ni autoengaño
Lo que es cierto: watchTowr vio explotación de ambas CVE en sus honeypots el 21 de octubre; Cloudflare detectó tráfico de ataque (la vulnerabilidad se filtró antes de la divulgación oficial); el NCSC británico sacó una alerta; y hay sondeos masivos —millones— con gente intentando soltar malware Mirai.
Lo que no es cierto, al menos todavía: no hay ni un solo compromiso de un sitio real confirmado públicamente. La explotación en masa resultó más difícil de lo que pareció el día del anuncio, precisamente por esas precondiciones. Así que la lección no es «relájate», es otra: parchea antes de ser tú la excepción.
Míralo moverse: el laboratorio en Docker
Una cosa es leer «el servidor débil filtra su estado» y otra es verlo pasar en una terminal. Así que armé un laboratorio en Docker —vive en su propio repositorio, listo para clonar— con dos servidores PHP que son gemelos salvo en una cosa: la configuración. Uno va mal configurado (versión vieja, display_errors encendido, upload_progress activo, memory_limit de juguete). El otro, endurecido. Y un tercer contenedor hace de auditor, que los revisa a los dos y te los pone lado a lado.
Lo de siempre, que no me cansaré de repetir: aquí no hay exploit. El auditor detecta la versión, repasa las precondiciones y lanza una sonda inofensiva —un marcador metido en un multipart— solo para enseñarte la diferencia. El servidor flojo devuelve el marcador y encima filtra un Fatal error por OOM; el endurecido responde un 403 seco y no suelta ni una pista.
Levantarlo es un comando:
git clone https://github.com/marcotorres/php2shell-demo.git
cd php2shell-demo && ./run.sh
run.sh construye las imágenes, espera a que los servidores estén sanos, corre la auditoría y desmonta todo al final. A la izquierda verás el servidor vulnerable en rojo —versión antigua, precondiciones de par en par, marcador reflejado— y a la derecha el endurecido en verde —parcheado, superficie mínima, sonda rebotada con un 403—. Ese contraste, a dos colores, es básicamente todo el post en una pantalla.
La shell —el plano que todos esperan— la verás más abajo. Y no solo la de PHP: en los tres stacks, uno al lado del otro.
Cómo blindar tu sitio: defensa en profundidad
Vamos a lo que de verdad te trajo hasta aquí. La protección se arma en cuatro capas, y el orden no es decorativo: la primera es la cura; las otras tres son contención y vigilancia, para mientras parcheas y para después.
Parchea PHP — la única cura real
No hay rodeo que te salve. El fallo está en el intérprete, así que la solución es actualizar el intérprete a una versión corregida. Y ojo con esto, que confunde a mucha gente: no son cuatro actualizaciones, es una por cada rama que sigue con soporte. Mira tu versión con php -v, ubica tu rama y salta al número que le toca —o a uno mayor dentro de esa misma rama—:
- Si corres PHP 8.5.x → 8.5.12
- Si corres PHP 8.4.x → 8.4.27
- Si corres PHP 8.3.x → 8.3.36
- Si corres PHP 8.2.x → 8.2.35
Y afecta a todos los modos de ejecución —PHP-FPM, Apache con mod_php, php-cgi, FrankenPHP, LiteSpeed—, así que no, no te libras por usar uno en vez de otro.
¿Estás en PHP 8.1 o anterior? Malas noticias con moraleja incluida: esas ramas ya están en fin de vida y no les llega parche oficial. Tu única salida de verdad es migrar a una versión soportada. Si lo venías posponiendo «para más adelante», pues bienvenido el empujón.
Pon un WAF al frente — contención inmediata
Mientras despliegas el parche por toda tu flota, un WAF te da aire para respirar. Cloudflare protege a sus clientes por defecto desde el 21 de octubre de 2026, 03:02 UTC, con una capacidad nueva —full transaction detection— que mira petición y respuesta juntas, dentro de la misma transacción HTTP, para cazar el patrón sin ahogarte en falsos positivos.
¿Que no usas Cloudflare? Una regla de ModSecurity que bloquee la sonda es un tapón temporal más que digno:
# Deniega la sonda de session upload progress en el borde.
SecRule ARGS_NAMES "@streq PHP_SESSION_UPLOAD_PROGRESS" \
"id:926001,phase:2,deny,status:403,log,msg:'php2shell probe blocked'"
Pero no lo confundas: esto es contención, no cura. El WAF te compra tiempo; el parche es el que cierra la herida.
Endurece la configuración — reduce la superficie
Por sí solo no previene la explotación (sobre ese matiz volvemos enseguida), pero borra las señales que busca el escáner y te saca de la lista de presas fáciles. En tu php.ini:
display_errors = Off ; nunca filtres errores al cliente
log_errors = On ; pero sí a tus logs
expose_php = Off ; sin X-Powered-By delatando la versión
session.use_strict_mode = 1 ; rechaza PHPSESSID que tú no emitiste
session.upload_progress.enabled = 0 ; apaga la vía confirmada del CVE
file_uploads = Off ; si no subes archivos, ciérralo
post_max_size = 1M ; y limita el multipart al mínimo
upload_max_filesize = 1M
Y en el servidor web, limita o bloquea multipart/form-data donde no te haga falta: es el formato con el que viaja la sonda.
Caza indicadores de compromiso — vigila
Parchear no te dice si ya intentaron colarse antes. Así que repasa tus logs buscando las huellas del ataque:
- Peticiones
multipartraramente grandes o muy anidadas. - Workers de PHP que se cayeron o tocaron su
memory_limit(el OOM del paso 1). - Ráfagas de errores 500 sobre el mismo endpoint.
- El marcador del escáner: el campo
PHP_SESSION_UPLOAD_PROGRESS, o archivos subidos con nombreMARKER_[8 hex].txt. - Y lo clásico tras un compromiso: web shells nuevos, cron jobs que no pusiste tú o cuentas colgando de los procesos de PHP.
Como referencia pública, se señaló la IP 206.188.197[.]105 como servidor de operaciones del atacante. Bloquéala y búscala en tu tráfico.
El matiz que casi nadie cuenta: los `.ini` no bastan
Cuidado con esta trampa, porque es peligrosa. watchTowr lo dijo sin rodeos: las mitigaciones que solo tocan archivos .ini hay que darlas por ineficaces para impedir la explotación. Endurecer la configuración reduce tu superficie y te saca del radar de los escáneres automáticos —por eso vale la pena hacerlo hoy mismo—, pero no cierra el agujero. Un atacante decidido que conozca tu servidor puede seguir encontrando vías. Lo único que elimina la vulnerabilidad de verdad es parchear. El resto es ganar tiempo. No confundas «me quité a los bots de encima» con «estoy a salvo», que no es lo mismo.
PHP2Shell no vino solo: la semana en que crujió el stack
Si solo te llevaras PHP2Shell de este artículo, te perderías la mitad de la historia —y, te diría, la mitad más interesante—. Porque esa misma semana de octubre de 2026 no cayó una grieta crítica, cayeron tres, una detrás de otra, y cada una en una pieza distinta del stack con el que montamos la web moderna.
Vamos una por una, rápido, porque la gracia está en lo que tienen en común:
14 de octubre · Next.js — el framework
El equipo de Next.js sacó un parche fuera de ciclo para CVE-2026-96889 (CVSS 9.5), un RCE sin autenticación que en realidad no vivía del todo en Next.js, sino en sharp, la librería que usa por debajo para procesar imágenes. Al colarle un SVG malicioso a la optimización de imágenes (piensa en next/og generando una ImageResponse con datos que no controlas), un fallo de memoria en esa librería nativa abría la puerta a ejecutar código. Afectaba a casi todas las versiones de los últimos años; se tapó en 15.5.28 y 16.4.1. De propina venían un segundo RCE en use cache (Cache Components) y un DoS en Server Actions.
20 de octubre · PHP — el lenguaje
El protagonista de este post: PHP2Shell (CVE-2026-109618/109619, CVSS 9.2), los dos use-after-free en el intérprete que ya diseccionamos arriba. El más gordo por alcance —toca a casi toda la web—, aunque, como vimos, también el más exigente en precondiciones para explotarse de verdad.
21 de octubre · Node.js — el runtime
Al día siguiente le tocó a Node.js: CVE-2026-111497 (CVSS 9.8, la nota más alta de las tres), una escritura fuera de límites en el decodificador Brotli que trae de serie. En cristiano: si tu proceso de Node descomprime datos Brotli que vienen de fuera —una petición HTTP con Content-Encoding: br, una respuesta de fetch, un frame de WebSocket— un atacante puede corromper memoria y, de ahí, llegar a ejecutar código. Se arregló en 22.23.4, 24.22.1 y 26.12.1, y el mismo release cerró otros nueve CVE de paso. Node 20.x y anteriores, en fin de vida, se quedan sin parche.
Y aquí está lo que de verdad quería que vieras. Mira las tres con los ojos entrecerrados y se te borran las diferencias de logo: ninguna de las tres vive en tu código. No son un if mal puesto ni una consulta sin sanear. Las tres son fallos de memoria —use-after-free, escritura fuera de límites— en el código nativo en C que sostiene todo lo demás: un intérprete, un decodificador de compresión, una librería de imágenes. Piezas que llevaban años ahí abajo, dándose por hechas, trabajando en silencio… hasta que la misma era de la IA que las encuentra las puso a todas bajo la lupa a la vez.
El plano del compromiso, en los tres (y por qué no duele igual)
Habrás visto esos videos donde, tras el exploit, llega el momento estrella: una shell escupiendo el usuario del proceso y corriendo comandos como si nada. El laboratorio reproduce ese plano en los tres stacks —y aquí viene lo que de verdad importa, y no es decorativo: el usuario con el que corre cada proceso. Ahí se decide cuánto duele.
Por qué no publico el exploit (y aun así puedes ver la shell)
Las tres vulnerabilidades están vivas y en explotación activa. Soltar un PoC funcional de cualquiera de las cadenas sería repartir un arma que funciona igual contra tu laboratorio que contra cualquier servidor sin parchear. Eso no lo hago.
El truco, que es honesto: la shell que ves es real, pero se abre de forma legítima, con docker exec sobre tus propios contenedores del laboratorio —sin exploit de por medio—. El usuario (www-data, root, nextjs), el id, el uname -a… todo es real (es el usuario con el que de verdad corre cada servicio). Lo único dramatizado son las líneas del «lanzamiento del exploit»: ahí hay texto, no código. Te muestro qué se ve tras un compromiso, no cómo provocarlo.
Tres stacks, el mismo tipo de grieta y tres finales muy distintos —no por el fallo, sino por cómo corres el proceso. Node como root se lo lleva todo; Next como usuario sin privilegios apenas sangra. La moraleja se cae de madura: no corras tus servicios como root, y el día que algo falle ahí dentro, dolerá muchísimo menos.
La lección, en una frase
Lo que te sostiene también es software —y también se rompe—. Tu intérprete, tu runtime y las librerías nativas de tu framework no los eliges con el corazón: los heredas. Por eso la única defensa que escala a las tres es la más aburrida y, a la vez, la más eficaz: mantener el stack al día. Un inventario de versiones y una rutina de parcheo valen, el día de una semana así, más que cualquier truco ingenioso.
Cierre
PHP2Shell es, al mismo tiempo, un susto y una lección. El susto está claro: un fallo en el corazón de PHP, con RCE sin autenticación, tocando a casi toda la web, y destapado en plena era en que la IA acelera por igual a quien defiende y a quien ataca. La lección es más tranquilizadora de lo que el titular sugiere: la mayoría de servidores no es explotable con los exploits públicos, porque hace falta una combinación de precondiciones que una instalación bien llevada sencillamente no regala. El pánico no toca; la diligencia, sí.
Y el plan entra en una frase: parchea ya —8.5.12, 8.4.27, 8.3.36, 8.2.35, o migra si estás en fin de vida—, mete un WAF mientras tanto, endurece para salir del radar y vigila tus logs por si alguien ya probó suerte en tu puerta. Nada de esto es exótico ni nuevo. Es la higiene de siempre —solo que esta semana con el cronómetro corriendo—.
Y si algo se lleva esta semana de tres grietas seguidas, más allá de PHP, es que el enemigo rara vez es tu código: es todo ese software heredado que te sostiene y que das por hecho. Next.js, PHP y Node.js cayeron por lo mismo, a tres días de distancia. La defensa que vale para los tres no es ninguna genialidad, es una costumbre: saber qué versiones corres y tener una rutina para actualizarlas. Aburrido, sí. También es lo que te salva.
¿Quieres que revise la exposición de tu sitio?
Fuentes
Divulgación y análisis técnico
- PHP2Shell — sitio oficial de la divulgación. php2shell.com — resumen de las dos CVE, el rol de la IA (Wiz Research, Gemini 4, GPT-5.6-Sol) y las PoC sobre WordPress, Drupal y Joomla.
- Sansec (2026). PHP2Shell: PHP RCE (CVE-2026-109618, CVE-2026-109619) — el detalle técnico del use-after-free, el unserializer de upload-progress y las condiciones de explotación.
- watchTowr (2026). PHP2Shell RCE Exploited: CVE-2026-109618 & CVE-2026-109619 — explotación observada en honeypots y el aviso de que las mitigaciones por
.inino bastan. - Tenable (2026). php2shell (CVE-2026-109618, CVE-2026-109619): Critical PHP RCE FAQ — preguntas frecuentes y versiones parcheadas.
Explotación, telemetría y mitigación
- The Hacker News (2026). PHP2Shell Exploit Attempts Hit Millions as Attackers Try to Deploy Mirai Malware — escala de los intentos de explotación y la botnet Mirai.
- Cloudflare (2026). Cloudflare deploys protections against php2shell vulnerability — protección WAF por defecto y full transaction detection.
- SocRadar (2026). PHP2Shell Exploit Tooling Found on Exposed Attacker Server — el tooling del atacante (
aslr_exploit.py), los IoC y los sitios sondeados sin compromiso confirmado.
La semana completa: Next.js y Node.js
- The Hacker News (2026). Next.js Ships Out-of-Band Patch for Two Critical RCE Flaws in Caching and SVG Processing — el RCE de
sharp/SVG (CVE-2026-96889) y el deuse cache. - Netlify (2026). Next.js & React security release (Oct 2026) — advisories, versiones afectadas y parches (15.5.28 / 16.4.1).
- Node.js / Astra (2026). Node.js Security Release (October 2026): Brotli RCE + 9 CVEs — el fallo del decodificador Brotli (CVE-2026-111497) y las versiones parcheadas (22.23.4 / 24.22.1 / 26.12.1).
- Qualys (2026). Node.js Patches Brotli Remote Code Execution Flaw — superficie de ataque (Content-Encoding: br, fetch, WebSocket) y cómo encontrar runtimes vulnerables.
Artículos relacionados
Dos skills para diseñar mejores interfaces con Claude Code: ui-ux-pro-max e impeccable
Claude Code programa muy bien, pero por defecto diseña interfaces del montón —las mismas plantillas SaaS de siempre—. Dos skills de la comunidad lo arreglan por lados distintos: ui-ux-pro-max le da criterio de diseño (design system, paletas, tipografía) e impeccable le da control de calidad (forma, accesibilidad, 61 reglas deterministas). Cómo se instalan, sus comandos y un ejemplo real: montar una frutería online.
La guía definitiva de Claude Code para desarrollo: carpetas, skills y flujos
Cómo se usa Claude Code de verdad para programar: el loop de trabajo, la arquitectura de carpetas que decide si te acelera o te frena, y qué skills conviene montar. Y lo que dice la evidencia —SWE-bench, el estudio de METR— cuando dejas el marketing de lado. Con todo citado a la documentación de Anthropic y a los papers.
