Blog

PHP2Shell: cómo parchear y mitigar CVE-2026-109618 y CVE-2026-109619

22 de octubre de 2026 · Jeremías Palazzesi

PHP2Shell: cómo parchear y mitigar CVE-2026-109618 y CVE-2026-109619

El 21 de octubre el equipo de PHP publicó parches para dos vulnerabilidades críticas en el núcleo del lenguaje, bautizadas PHP2Shell: CVE-2026-109618 y CVE-2026-109619. Las dos permiten ejecución remota de código sin autenticación y tienen un puntaje CVSS 4.0 de 9.2. Amazon Threat Intelligence detectó intentos de explotación desde el 17 de octubre, cuatro días antes de que existiera el parche.

Afecta a toda instalación de PHP que atienda pedidos web: PHP-FPM, Apache con mod_php, php-cgi, FrankenPHP y LiteSpeed. Según el aviso oficial, el riesgo es mayor con mod_php. No importa qué CMS o framework uses: la falla está en PHP, antes de que llegue a correr tu código.

Qué se rompe

  • CVE-2026-109618 — corrupción por falta de memoria. Cuando PHP se queda sin memoria, el manejo del error puede cortar la ejecución con los datos internos del pedido a medio inicializar.
  • CVE-2026-109619 — estado global obsoleto. Estado interno que pertenece a un pedido sobrevive después de que se liberó la memoria que lo respaldaba. El camino confirmado pasa por el seguimiento de subidas de sesión (session.upload_progress).

1. Parchear: la única solución completa

El aviso de PHP es claro: no hay mitigaciones completas, actualizar es la única opción segura. Las versiones corregidas son:

  • PHP 8.5.12
  • PHP 8.4.27
  • PHP 8.3.36
  • PHP 8.2.35 (8.2 llega al fin de soporte el 31/12/2026)

PHP 8.1 y anteriores ya no reciben actualizaciones del proyecto. Hay ramas con el parche portado para 7.4, 8.0 y 8.1 en el repositorio de php-src, pero lo razonable es pedirle el paquete a tu distribución o a tu proveedor de soporte extendido, y planificar la migración.

Debian / Ubuntu

Las distribuciones portan el arreglo sin cambiar el número de versión de PHP, así que no te guíes por php -v: fijate en la versión del paquete. En Ubuntu el aviso es el USN-8948-1.

sudo apt update
sudo apt install --only-upgrade 'php8.*'
apt changelog php8.3-fpm | grep -m3 CVE-2026-1096    # cambiá 8.3 por tu versión
sudo systemctl restart php8.3-fpm    # o apache2 si usás mod_php

RHEL, Rocky, Alma (Remi o AppStream)

sudo dnf upgrade 'php*'
sudo systemctl restart php-fpm httpd

Contenedores

Reconstruí las imágenes sobre la etiqueta oficial actualizada (docker pull php:8.3-fpm o la que uses) y volvé a desplegar. Una imagen vieja corriendo en producción sigue vulnerable aunque el host esté parcheado.

Hosting compartido

Revisá en el selector de PHP del panel si ya está la versión corregida. Si el proveedor todavía no la publicó, pasá a las mitigaciones de abajo y reclamale el parche.

Después de actualizar

  • Reiniciá todos los workers (FPM, Apache, LiteSpeed). Un proceso que sigue vivo sigue corriendo el binario viejo.
  • Comprobá la versión que atiende la web, no la de la consola: suelen ser binarios distintos. Un archivo temporal con <?php echo PHP_VERSION; y borralo enseguida.
  • Revertí las mitigaciones temporales una vez verificado el parche, sobre todo los cambios de memory_limit.

2. Mitigar mientras no puedas actualizar

Ninguna de estas medidas cierra todo. Reducen la superficie y compran tiempo hasta el parche.

Apagar el seguimiento de subidas de sesión (CVE-2026-109619)

Tiene que aplicarse antes de que PHP procese el pedido: en php.ini, en el pool de FPM o en la configuración del servidor. No sirve con ini_set() ni con .user.ini de FPM. Reiniciá todos los workers después.

; php.ini
session.upload_progress.enabled = 0

; pool de PHP-FPM (www.conf)
php_admin_flag[session.upload_progress.enabled] = off

# Apache con mod_php (sólo en el vhost: en .htaccess da error 500)
php_admin_flag session.upload_progress.enabled off

En PHP 8.5 agregá además fatal_error_backtraces = 0. Y sacá configuraciones inválidas u obsoletas que se apliquen por pedido y generen avisos: esconder los errores con display_errors o @ no ayuda.

Achicar los pedidos (CVE-2026-109618)

post_max_size = 8M          ; 32M si la aplicación recibe archivos
upload_max_filesize = 6M    ; siempre por debajo de post_max_size

Reforzalo en el servidor web o el proxy, que corta antes de que el pedido llegue a PHP: LimitRequestBody en Apache, client_max_body_size en Nginx, y límites de cantidad de campos, partes multipart y encabezados donde tu WAF lo permita.

El aviso oficial también propone memory_limit = -1 fijado con php_admin_value para que la aplicación no lo pueda cambiar. Ojo: sin límite, un solo pedido puede comerse toda la RAM del servidor. Si lo aplicás, poné un límite por contenedor o cgroup que mate sólo al worker afectado, y no uses RLIMIT_AS ni RLIMIT_DATA, que justamente disparan la falla.

Bloquear multipart donde no se suben archivos

Rechazar multipart/form-data en el servidor web o en el WAF para las rutas que no reciben archivos corta buena parte de los ataques, aunque no todos. Una advertencia de nuestra experiencia aplicándolo esta semana: muchos formularios mandan FormData por JavaScript aunque no tengan archivos, y eso también viaja como multipart. Contactos, carritos y puntos de venta dejaron de funcionar en las primeras pruebas. Antes de bloquear una ruta, buscá todos los new FormData del frontend y probá cada formulario.

# Apache: bloquea multipart salvo en las rutas que suben archivos
RewriteEngine On
RewriteCond %{HTTP:Content-Type} multipart/form-data [NC]
RewriteCond %{REQUEST_URI} !^/(admin|api/upload)
RewriteRule ^ - [F]

Si tenés el sitio detrás de Cloudflare, Azure Front Door o similar, la misma regla en el borde es todavía mejor.

3. Revisá si ya te tocaron

Hubo explotación antes del parche, así que actualizar no alcanza: hay que mirar hacia atrás desde el 17 de octubre.

# PHP nuevos en carpetas de subidas o caché
find /var/www -name '*.php' -newermt 2026-10-17 \( -path '*upload*' -o -path '*cache*' -o -path '*tmp*' \)

# patrones típicos de webshell
grep -rlE 'eval\(base64_decode|assert\(\$_|system\(\$_|passthru\(\$_' /var/www --include=*.php

# workers que se caen: puede ser un intento
grep -iE 'segfault|SIGSEGV|SIGBUS' /var/log/php*-fpm.log /var/log/apache2/error.log

# pedidos multipart con el campo de progreso de subida
zgrep -i 'PHP_SESSION_UPLOAD_PROGRESS' /var/log/apache2/access.log*

Sumale una mirada a cron, usuarios nuevos, claves SSH autorizadas y conexiones salientes raras. Si encontrás algo, no lo borres sin antes copiarlo: es la evidencia para entender qué pasó.

Resumen

  • Hoy: actualizá PHP a 8.2.35, 8.3.36, 8.4.27 u 8.5.12 (o el paquete corregido de tu distro) y reiniciá todos los workers.
  • Si no podés: session.upload_progress.enabled = 0, límites de tamaño bajos y bloqueo de multipart probado ruta por ruta.
  • En los dos casos: revisá indicios de compromiso desde el 17/10.

En Fundamenta aplicamos estas medidas en los servidores que administramos mientras esperábamos los parches. Si necesitás ayuda para actualizar, mitigar o revisar un servidor, escribinos a info@fundamenta.ar o desde fundamenta.ar/servicios.

Fuentes: aviso de seguridad de PHP · GHSA-w8hw-w9fx-j79w · GHSA-6wmf-4rv5-p3rp · BleepingComputer · Sansec.

¿Tenés una consulta sobre este tema?

Contanos qué tenés y lo vemos juntos, sin compromiso.