php2shell (CVE-2026-109618): cómo saber si tu PHP es vulnerable y cómo actualizarlo

Foto de Marco Orta | 9 min de lectura
Portada tipográfica: «php2shell» en grande sobre fondo de terminal, con un diff que cambia PHP 8.4.26 (vulnerable) por PHP 8.4.27 (corregida) al correr php -v dentro del contenedor
Tabla de Contenidos

    php2shell es el nombre que se le dio a dos fallas críticas en el núcleo de PHP, CVE-2026-109618 y CVE-2026-109619, publicadas el 21 de octubre de 2026. Las dos tienen severidad CVSS v4 de 9.2 y permiten ejecutar código en el servidor sin iniciar sesión. Las versiones corregidas son 8.5.12, 8.4.27, 8.3.36 y 8.2.35. Si tu PHP tiene un número menor dentro de su rama, hay que actualizar hoy: según el aviso oficial de php.net, no hay mitigaciones completas y actualizar es la única opción segura.

    Abajo explico cómo saber qué versión corre de verdad (que no siempre es la que dice la terminal), cómo actualizar según dónde vive tu PHP, la trampa en la que caí yo mismo con Docker el día del aviso, qué hacer si hoy no puedes actualizar y qué pasa con PHP 8.1 y anteriores. Al final hay una sección para dueños de negocio que no van a abrir una terminal.

    Qué es php2shell, en corto

    Son dos vulnerabilidades distintas que se corrigieron en la misma entrega:

    • CVE-2026-109618 (GHSA-w8hw-w9fx-j79w): cuando PHP se queda sin memoria a la mitad de preparar una petición, la limpieza posterior puede tratar como válidos datos que estaban a medio inicializar.
    • CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp): parte del estado de una petición puede sobrevivir después de que se libera su memoria, y una petición posterior atendida por el mismo proceso lo usa antes de que se reinicie.

    Según php.net, el riesgo alcanza a toda instalación de PHP que atiende peticiones web: PHP-FPM, Apache con mod_php, php-cgi, FrankenPHP y LiteSpeed. Consideran mayor el riesgo en mod_php. El detalle técnico está en los dos avisos de GitHub; aquí no hace falta para actualizar.

    El nombre viene de una herramienta de prueba de concepto que circuló el 20 de octubre, antes de que terminara el embargo. Por eso el equipo de PHP adelantó la publicación.

    Las versiones corregidas

    RamaVersión corregidaSoporte de seguridad de la rama
    8.58.5.12hasta 31-dic-2029
    8.48.4.27hasta 31-dic-2028
    8.38.3.36hasta 31-dic-2027
    8.28.2.35hasta 31-dic-2026
    8.6 (en pruebas)8.6.0 RC4no usar en producción
    8.1 y anterioressin versión oficialver la sección de 8.1

    Fuentes: aviso de seguridad de php.net y versiones soportadas. Si estás en 8.2, el parche de hoy te protege de php2shell, pero la rama se queda sin parches en diez semanas; lo explico en PHP 8.2 se queda sin parches el 31 de diciembre.

    Cómo saber si tu PHP es vulnerable

    La regla es simple: compara tu versión con la tabla. Lo difícil es saber cuál es «tu versión».

    En el servidor:

    php -v          # la PHP de la terminal (CLI)
    php-fpm -v      # o php-fpm8.4 -v, según la distro: la que atiende la web
    

    En un servidor con varias versiones instaladas, la CLI puede ser 8.4 y la web seguir en 8.2. La que importa es la que atiende peticiones: PHP-FPM, mod_php o el binario que use tu servidor web.

    En Docker, nunca en tu laptop ni en la imagen que crees que desplegaste. Dentro del contenedor que está corriendo:

    docker exec <contenedor> php -v
    docker exec <contenedor> php-fpm -v
    

    Desde la aplicación, si no tienes acceso al servidor: un archivo temporal con <?php echo PHP_VERSION; en una ruta que nadie conozca, lo abres una vez y lo borras. No dejes un phpinfo() publicado.

    Ojo con los paquetes de tu distribución

    Debian, Ubuntu, Red Hat y sus derivados suelen meter el parche en su propio paquete sin cambiar el número de versión de PHP. Un PHP 8.2 de Debian puede decir 8.2.algo menor que 8.2.35 y estar corregido. Ahí no te sirve la tabla: lo que manda es el registro de cambios del paquete.

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

    Si aparecen los dos CVE, ese paquete ya trae la corrección. Si no, todavía no.

    Cómo actualizar, según dónde corre tu PHP

    Docker

    Las imágenes oficiales ya están publicadas: php:8.4.27-*, php:8.5.12-*, php:8.3.36-* y php:8.2.35-* en Docker Hub, y serversideup/php:8.4.27-* también. El orden que funciona:

    1. Fija la versión de parche en el FROM si puedes (php:8.4.27-fpm). Con un tag movible como php:8.4-fpm dependes de que tu servidor y tu CI vuelvan a descargarlo.
    2. Reconstruye sin caché de la imagen base: docker build --pull ... obliga a descargar la base nueva.
    3. Despliega una imagen nueva y asegúrate de que tu plataforma de verdad la construya (abajo cuento por qué lo digo).
    4. Comprueba dentro del contenedor con php -v y php-fpm -v. El semáforo verde del deploy no dice qué versión de PHP quedó.

    Si usas una imagen base propia que hereda de la oficial, son dos reconstrucciones: primero la base, luego la app.

    Servidor con paquetes (apt, dnf)

    php.net dice que las distribuciones y los proveedores de LTS recibieron los parches por adelantado, así que lo normal es que ya haya paquete:

    # Debian / Ubuntu
    sudo apt update && sudo apt install --only-upgrade 'php8.4*'
    sudo systemctl restart php8.4-fpm     # y apache2 si usas mod_php
    
    # RHEL y derivados
    sudo dnf upgrade 'php*'
    sudo systemctl restart php-fpm
    

    Ajusta 8.4 a tu rama. Reiniciar es parte de la actualización: el proceso de PHP que ya estaba corriendo sigue con el código viejo en memoria hasta que lo reinicias.

    Un caso aparte: si instalaste PHP desde el repositorio de Remi (rpms.remirepo.net), el aviso de php.net pide cambiar a los paquetes de tu distribución o compilar, porque ese repositorio, mantenido por voluntarios, no iba a tener actualizaciones el 21 de octubre.

    Hosting compartido (cPanel, Plesk)

    En hosting compartido, quien actualiza PHP es el proveedor, no tú. Lo que sí puedes hacer:

    • Revisar la versión en Seleccionar versión de PHP o MultiPHP Manager (cPanel), o en la configuración de PHP del dominio (Plesk).
    • Si estás en una rama vieja, subir a 8.3, 8.4 o 8.5 desde ese mismo selector, después de probar que tu sitio funciona con ella.
    • Escribirle al soporte y preguntar, por escrito, si ya aplicaron la versión corregida en tu servidor.

    WordPress

    WordPress no trae PHP: usa el del servidor. Actualizar WordPress o sus plugins no corrige php2shell. Para ver qué versión usa tu sitio, entra a Herramientas → Salud del sitio → Información → Servidor. Si la versión es menor a la de la tabla, el arreglo va por el hosting (sección anterior) o por tu servidor, si administras uno.

    Antes de cambiar de rama (de 8.1 a 8.3, por ejemplo), revisa que tu tema y tus plugins la soporten: es el punto donde los sitios viejos suelen romperse.

    La trampa del redeploy: lo que me pasó el 21 de octubre

    Mi backend corre en Docker sobre la imagen serversideup/php:8.4-fpm-nginx, desplegado con Coolify desde la CI. Antes de tocar nada, esto decía el contenedor en producción:

    + docker ps --filter name=jd0k… --format "{{.Names}}  {{.Image}}  {{.Status}}"
    jd0k…-20261021T001519  jd0k…:f2863d8…  Up 18 hours (healthy)
    + docker exec … php -v
    PHP 8.4.26 (cli) (built: Oct  6 2026 01:25:30) (NTS)
    Copyright (c) The PHP Group
    Built by https://github.com/docker-library/php
    Zend Engine v4.4.26, Copyright (c) Zend Technologies
        with Zend OPcache v8.4.26, Copyright (c), by Zend Technologies
    

    8.4.26: vulnerable. Reconstruí mi imagen base sobre 8.4.27, la publiqué y la bajé al servidor. La base nueva ya traía la versión corregida:

    + docker pull ghcr.io/ortamarco/ombackend-php-base:8.4
    8.4: Pulling from ortamarco/ombackend-php-base
    …
    Digest: sha256:8a2f70…
    Status: Downloaded newer image for ghcr.io/ortamarco/ombackend-php-base:8.4
    + docker run --rm --entrypoint php ghcr.io/ortamarco/ombackend-php-base:8.4 -v
    PHP 8.4.27 (cli) (built: Oct 21 2026 15:53:31) (NTS)
    

    Relancé el deploy desde la CI. Salió verde, el contenedor nuevo arrancó healthy, y esto fue lo que encontré al revisar:

    # 12:28, tras el docker pull de la base 8.4.27 y relanzar la CI (mismo commit f2863d8):
    + docker ps --filter name=jd0k… …
    jd0k…-20261021T182804  Up About a minute (healthy)
    + docker exec … php -v
    PHP 8.4.26 (cli) (built: Oct  6 2026 01:25:30) (NTS)
    + docker exec … php-fpm -v
    PHP 8.4.26 (fpm-fcgi) (built: Oct  6 2026 01:25:30) (NTS)
    

    Seguía en 8.4.26. Coolify vio que el deploy era del mismo commit y, como la CI lo pide sin forzar (force=false), reutilizó la imagen que ya había construido para ese commit. La base nueva estaba en el servidor y nadie la usó.

    La salida fue un commit nuevo, que obliga a reconstruir. Después de ese deploy:

    + docker ps --filter name=jd0k… --format "{{.Names}}  {{.Image}}  {{.Status}}"
    jd0k…-20261021T183708  jd0k…:cac8d90…  Up 30 seconds (healthy)
    + docker exec … php -v
    PHP 8.4.27 (cli) (built: Oct 21 2026 15:53:31) (NTS)
    + docker exec … php-fpm -v
    PHP 8.4.27 (fpm-fcgi) (built: Oct 21 2026 15:53:31) (NTS)
    

    Ahora sí, 8.4.27 en la CLI y en FPM. Ese mismo día aproveché para subir el backend a PHP 8.5.12.

    Lo que me llevo, y aplica a cualquier plataforma que despliegue imágenes (Coolify, un pipeline propio, Kubernetes):

    • Un tag movible (:8.4) se queda en la caché del servidor y de la CI. Bajarlo no basta si la plataforma decide no reconstruir.
    • Un redeploy del mismo commit puede reutilizar la imagen anterior. Forza la reconstrucción (opción de force rebuild, --no-cache, --pull) o empuja un commit nuevo.
    • La única evidencia que vale es php -v dentro del contenedor que atiende el tráfico. «Deploy exitoso» y «contenedor sano» los tuve los dos con la versión vulnerable.

    Si hoy no puedes actualizar

    El aviso de php.net trae medidas que reducen la exposición a rutas de ataque concretas, pero no hacen segura la instalación. Sirven para ganar horas mientras preparas la actualización:

    • session.upload_progress.enabled=0 y reiniciar todos los procesos de PHP. Tiene que ir en php.ini, en el pool de FPM o en la configuración del servidor; ini_set() y .user.ini no sirven, porque se aplican tarde.
    • memory_limit=-1, de preferencia con php_admin_value en el pool de FPM o en Apache para que la aplicación no pueda cambiarlo, y revisando que ningún otro lado vuelva a poner un límite. No lo sustituyas con RLIMIT_AS ni RLIMIT_DATA: el aviso dice que pueden provocar justo la falla de memoria vulnerable. Pon un límite de memoria al contenedor o cgroup para que un proceso no se coma el servidor.
    • post_max_size bajo: 8M si tu aplicación no recibe archivos, 32M si sí. Y upload_max_filesize por debajo de post_max_size.
    • Solo en PHP 8.5: fatal_error_backtraces=0 y reiniciar los procesos.

    Ocultar errores con error_reporting, display_errors o @ no ayuda.

    CISA agrega dos cosas: que un WAF puede dar algo de protección temporal mientras actualizas, y que si no puedes parchar, o si sigues en PHP 8.1 o anterior, saques esos sistemas de línea hasta que estén corregidos. Si tienes un WAF delante, úsalo como paliativo mientras actualizas, nunca en lugar de actualizar.

    PHP 8.1 y anteriores

    El proyecto PHP ya no publica versiones de 8.1, 8.0 ni 7.4, así que no hay un 8.1.x oficial con la corrección. Lo que sí existe, y conviene decirlo con precisión:

    • Por la gravedad del caso, el equipo de seguridad de PHP publicó parches mínimos de código fuente para PHP 7.4, 8.0 y 8.1. Sirven si compilas PHP tú mismo.
    • Algunas distribuciones y proveedores de soporte extendido retroportan la corrección a sus paquetes de versiones viejas. Pregúntale al tuyo o revisa el changelog del paquete como expliqué arriba.
    • La salida de fondo es subir a una rama con soporte. En un sistema viejo eso casi nunca es solo cambiar el número: hay que revisar el framework y las librerías, y por eso no es un trabajo de una tarde.

    Si tienes un negocio y no vas a abrir una terminal

    Si tu tienda en línea, tu portal o tu sistema interno está hecho en PHP (WordPress, Laravel, un sistema a la medida), mándale hoy estas tres preguntas a quien te lo mantiene:

    1. ¿En qué versión de PHP corre mi sistema?
    2. ¿Ya se actualizó a la versión corregida del 21 de octubre? Pídele la salida de php -v como evidencia.
    3. Si es PHP 8.1 o anterior, ¿cuál es el plan y para cuándo?

    Si estás en hosting compartido, la pregunta va al hosting. Y si nadie te contesta, o ya no tienes a quién preguntarle, en El programador que hizo tu sistema ya no está explico qué asegurar primero.

    Si prefieres que lo haga yo: tengo una actualización urgente de PHP por $2,900 MXN + IVA por servidor o sitio, en 24 horas hábiles, para PHP en la rama 8.2 a 8.5: respaldo, actualización a la versión corregida, prueba y la salida de php -v como evidencia. Si tu PHP es 8.1 o anterior, no hay atajo de 24 horas; eso va al diagnóstico de rescate de 5 días hábiles por $9,900 MXN + IVA, con un plan de migración. El exprés se acredita a ese diagnóstico si después lo necesitas. Y si quieres calcular lo que cuesta tener el sistema al día todo el año, lo desgloso en cuánto cuesta mantener un sistema a medida.

    Preguntas frecuentes

    ¿Qué es php2shell?

    Es el nombre con el que se conocen dos vulnerabilidades críticas del núcleo de PHP, CVE-2026-109618 y CVE-2026-109619, publicadas el 21 de octubre de 2026. Las dos tienen severidad CVSS v4 de 9.2 y permiten ejecución remota de código sin autenticación en instalaciones de PHP que atienden peticiones web (PHP-FPM, Apache con mod_php, php-cgi, FrankenPHP y LiteSpeed).

    ¿Qué versiones de PHP corrigen php2shell?

    PHP 8.5.12, 8.4.27, 8.3.36 y 8.2.35, además de PHP 8.6.0 RC4 para quien prueba la versión en desarrollo. Según php.net no hay mitigaciones completas y actualizar es la única opción segura.

    ¿Cómo sé si mi PHP es vulnerable?

    Corre php -v y php-fpm -v en el servidor, o docker exec <contenedor> php -v si usas Docker, y compara con la versión corregida de tu rama. Si usas paquetes de Debian, Ubuntu o Red Hat, el número puede no cambiar: revisa el changelog del paquete (apt changelog o rpm -q --changelog) y busca CVE-2026-109618 y CVE-2026-109619.

    ¿Hay parche de php2shell para PHP 8.1, 8.0 o 7.4?

    No hay versión oficial publicada, porque esas ramas ya no reciben actualizaciones del proyecto PHP. El equipo de seguridad de PHP publicó parches mínimos de código fuente para 7.4, 8.0 y 8.1, útiles si compilas PHP, y algunas distribuciones y proveedores de soporte extendido retroportan la corrección. La solución de fondo es subir a una rama con soporte.

    ¿Basta con un WAF o con cambiar php.ini?

    No. Las medidas del aviso de php.net (desactivar session.upload_progress, memory_limit=-1, bajar post_max_size y, en PHP 8.5, fatal_error_backtraces=0) reducen la exposición a rutas de ataque concretas pero no hacen segura la instalación. CISA dice que un WAF puede dar protección temporal. Solo actualizar corrige las fallas.

    ¿php2shell afecta a WordPress?

    Afecta al PHP sobre el que corre WordPress, no a WordPress en sí. Actualizar WordPress o los plugins no lo corrige: hay que actualizar PHP en el servidor o pedírselo al hosting. La versión se ve en Herramientas, Salud del sitio, Información, Servidor.

    ¿Ya se está explotando php2shell?

    CISA dijo al publicar su alerta del 21 de octubre que no había observado explotación. La empresa de seguridad watchTowr reportó intentos de explotación de las dos fallas. Una prueba de concepto circuló el 20 de octubre, antes del fin del embargo, así que conviene actualizar sin esperar.

    Actualicé la imagen de Docker y redesplegué, ¿ya estoy protegido?

    No necesariamente. Un tag movible como php:8.4 queda en caché, y algunas plataformas reutilizan la imagen ya construida si el commit no cambió. Comprueba con php -v y php-fpm -v dentro del contenedor que atiende el tráfico; si sigue en la versión vieja, fuerza la reconstrucción o despliega un commit nuevo.

    Fuentes

    ¿Te sirvió? Compártelo

    ¿Te sirvió? Recibe la próxima por correo

    Una vez por semana: qué se rompe al actualizar, IA para desarrolladores y lo que estoy construyendo, con fuentes. Sin spam.

    Al suscribirte aceptas nuestro aviso de privacidad.

    Buscar

    Etiquetas

    PHP IA Laravel Migración JavaScript Tutorial Seguridad Desarrollo Web Upgrade Buenas Prácticas Agentes MCP OpenAI SEO Backend