Operación PHP2Shell
El 21 de Octubre de 2026, el ecosistema de PHP experimentó un evento de seguridad crítico de impacto global debido al descubrimiento de dos vulnerabilidades que permitían ejecutar código remoto, conocidas como PHP2Shell (CVE-2026-109618, CVE-2026-109619)
Recién me voy recuperando de una de las jornadas sin sueño más cabronas que he tenido, y quiero registrar el timeline de cómo lo viví, decisiones y aprendizajes de éste evento
3am - Señal de alerta
Me enteré de la vulnerabilidad por ahí de las 3am del 21 de Octubre, me topé un twit de The PHP Foundation y un par de comentarios mencionaban que se podía ejecutar código remoto con una simple llamada HTTP al servidor, no login, no acceso SSH, una vulnerabilidad crítica masiva que potencialmente afectariá 70% de internet
Me quitó el sueño, seguí leyendo posts de especialistas en seguridad, gente importante de PHP, varios compartieron recomendaciones para mitigar el riesgo, cada vez más de ellos mencionaban que no había manera real de mitigarlo hasta el parche
Mientras tanto, hackers en todo el mundo se habían enterado y estaban empezando a explotar la vulnerabilidad...
4am - Decisiónes
Para este punto, llevaba una hora pensando en cómo proteger nuestro sistema. La solución que mencionaban todos era esperar. Para mi esa no parecía una solución realmente, así que tomé la decision de directamente poner offline producción. Habilité el modo mantenimiento, se bloqueó todo trafico a nivel red y por 9 horas todos nuestros usuarios perdieron acceso al sistema
Nunca había tomado una decisión como ésta sin autorización... confié en mi instinto, horas después, aparecieron los twits de de la primera ministra de Japón y el departamento de Ciberseguridad de la Agencia de Seguridad Nacional de Estados Unidos
8am - La llegada del parche no fue suficiente
El parche oficialmente llegó y en cuanto me enteré, preparé el deploy con la configuración necesaria para actualizar la versión de PHP de producción
Las versiones que recibieron el parche fueron
- 8.5.12
- 8.4.27
- 8.3.36
- 8.2.35
Y nuestra app estaba utilizando la versión 8.3.30, por lo que la solución era tan simple como actualizarla a 8.3.36, no breaking changes
El problema fue enterarme que nuestro entorno de producción no tendría acceso al parche... Por límites de nuestro proveedor, la versión máxima disponible para nuestro flujo de despliegue era la 8.3.30 y no iba a ser actualizada... en absoluto, sin fecha estimada de llegada
Cuando me enteré que tenía que cambiar el flujo de despliegue para cubrir el parche de seguridad empezó el verdadero reto
9am - Arquitecturas resilientes
Afortunadamente, decisiones técnicas que en algún momento se pueden sentir sobre-pensadas un día dan rendimientos
Cuando llegué a la empresa, todo el sistema vivía en un monolito: Un VPS barebones que gestionaban todo el proyecto: migraciones, archivos, datos, cron jobs. El equipo utilizaba un script para hacer deploy desde una maquina local, se conectaba vía SSH al servidor de prod y sobreescribía los archivos del proyecto. Ésta arquitectura no es mala per sé, funciona, pero es muy peligrosa, un solo punto de fallo afecta al sistema completo
En 2024, después de una crisis de seguridad importante que tuvimos, presenté mi propuesta arquitectónica y entre varias otras mejoras de seguridad, migramos a un modelo desacoplado, separando las responsabilidades de infraestructura en 4 capas:
- Código
- Cómputo
- Archivos
- Datos
Cada capa con su propio esquema de mantenimiento y controles de seguridad
Para el caso de Cómputo, en la empresa empezamos a utilizar App Platform (Digital Ocean) para desplegar el código dockerizado, independiente de las demás capas. Equivalente a (y compatible con) Heroku, App Platform utiliza Cloud Native Buildpacks para asumir las tecnologías necesarias para ejecutar el código; El builder lee los archivos del repositorio y construye una imagen de Docker haciendo un guess de las dependencias de nivel OS necesarias y las instala. Es una solución zero config que en la gran mayoría de casos acierta, y para algunos casos más complejos como el nuestro, lee un archivo project.toml para determinar los buildpacks específicos necesarios
Fast-forward a Octubre 2026
El parche de seguridad para PHP se publicó. Heroku actualizó inmediatamente su Buildpack de PHP a la versión 299 que ya incluye el parche, pero Digital Ocean no actualizó la suya, a la fecha sigue utilizando la versión 281 del Buildpack y no se ha pronunciado al respecto
Yo no sabía cómo la estaba pasando el resto del mundo, para mi ya había pasado una hora desde la salida del parche y nuestra app de producción seguía offline
Mi primer instinto fue usar directamente la tecnología de Cloud Native Buildpacks para construir la imagen nosotros y cambiar la configuración de App Platform para usarla, es decir, hacer nosotros el buildstep
Trabajar exclusivamente sobre la capa de Cómputo sin afectar las demás
10am - Rework de la capa de Cómputo
Instalé pack y mis pruebas locales resultaron bien. Ya estaba, lo único que restaba era cargar la imagen a un registry y configurar App Platform para usarla
Pronto actualizaré esta sección con los detalles de cómo lo resolví
1pm - Deploy exitoso
Después de revisar que staging estaba funcionando correctamente, decidí levantar prod. Redirigí el trafico al nuevo ambiente y avisé a mi equipo
Después hubo silencio, por horas no recibí ningún mensaje. Pero en lugar de preocuparme eso me alivió, mi dicho es que si no hay feedback, no hay problema. Si los usuarios no están quejándose significa que todo está en orden. Aún así, tocó esperar
Después de monitorear que los usuarios estuvieron utilizando la app con normalidad por un par de horas, mi sistema biológico de alerta se apagó, y mi cuerpo recordó que llevaba 30 horas sin dormir
En cuanto me recosté en la cama, morí
11pm - Misión cumplida
Después de dormir todo el día, una sensación de preocupación me despertó de golpe, pero cuando vi que no había notificaciones del trabajo lo supe, la operación había sido un éxito
Nuestro producto se mantuvo seguro gracias a decisiones acertadas de arquitectura, un interés genuino por las tecnologías que utilizamos y la habilidad de responder rápido a la vulnerabilidad
Hasta ahora sigo leyendo historias de terror de cómo ésta vulnerabilidad sigue afectando a miles de servidores, especialmente sistemas legacy que dependen de versiones antiguas de PHP seguirán apagando fuegos durante las próximas semanas