← Volver al blog

24/10/2026

Salió una vulnerabilidad crítica en PHP y yo ni uso PHP: así revisé y parché todo mi stack

Esta semana salió una vulnerabilidad crítica en PHP —de esas que los medios de seguridad llaman "ejecución remota de código sin autenticación"— y casi al mismo tiempo empezaron a circular avisos sobre Python, sobre librerías que usa medio mundo y sobre paquetes que uno ni sabe que tiene instalados. Mi primera reacción fue la de siempre: abrir el celular, leer los titulares y sentir ese pequeño nudo en el estómago de "¿esto me toca?".

La segunda reacción fue la que quiero contarte aquí, porque creo que sirve para cualquier persona que tenga algo corriendo en un servidor, sea una tienda, un sistema interno o un proyecto personal: no asumir nada, y revisar de verdad.

Primero, la pregunta incómoda: ¿qué tengo realmente?

Parece una pregunta tonta, pero responderla con honestidad toma tiempo. Yo tengo varias aplicaciones propias en producción —una de agendamiento con pagos, un par de herramientas de gestión, este mismo sitio y un convertidor de documentos— todas en contenedores, todas en un mismo servidor. Y varios proyectos más que solo corren en mi computador.

Antes de tocar una sola línea de código hice un inventario: qué lenguaje usa cada una, qué versión exacta, qué librerías, qué sistema operativo hay debajo y qué programas corren en el servidor por fuera de mis aplicaciones. Y ahí apareció la primera buena noticia: de PHP no tengo ni una sola línea. Ningún proyecto, ningún servidor. Esa alerta tan ruidosa, para mí, no aplicaba.

Es un alivio, pero también una lección: gran parte de reaccionar bien a una vulnerabilidad es saber a tiempo cuándo no te afecta y quedarte tranquilo con evidencia, no con intuición.

Lo de Python sí me tocaba (y no solo por Python)

Aquí vino la parte interesante. Lo que corre dentro de un contenedor no es lo que dice tu archivo de requisitos —es lo que realmente quedó instalado la última vez que se construyó la imagen. Así que en vez de fiarme del archivo, le pedí a cada contenedor en producción la lista real de lo que tenía instalado y la crucé con las bases de datos públicas de vulnerabilidades.

El resultado fue bastante honesto:

  • Los marcos web (Flask y su motor interno) tenían avisos menores, de esos que requieren una combinación muy particular de condiciones para explotarse, pero que igual conviene cerrar.
  • Una librería de imágenes tenía cerca de cuarenta avisos acumulados. Cuarenta, en una sola librería.
  • Las de manejo de PDF, que son las que más me importan porque algunas de mis aplicaciones reciben archivos que suben otras personas, tenían varios avisos también.
  • Hasta la lista de entidades de confianza para conexiones seguras necesitaba actualizarse, porque una de ellas había sido comprometida y revocada.
  • Y debajo de todo, el propio Python de las imágenes y el sistema operativo del servidor tenían parches pendientes.

Nada de esto era una catástrofe, pero tampoco era "no pasa nada". Era exactamente el tipo de deuda silenciosa que se acumula cuando algo funciona bien y nadie lo toca.

El problema de fondo: versiones que se mueven solas

Lo que más me llamó la atención no fue ninguna vulnerabilidad en particular, sino algo que descubrí al tratar de actualizar: en varios de mis proyectos yo había fijado las versiones de las librerías que usaba directamente, pero no las de las librerías que esas librerías necesitan por debajo. Es decir: cada vez que reconstruía un contenedor, esas piezas de abajo podían cambiar solas, sin avisarme.

En uno de los proyectos ni siquiera había versiones fijas. Cuando probé una reconstrucción "limpia", varias piezas saltaron de versión mayor sin que yo hubiera pedido nada. Eso, en un sistema que funciona hoy, es una bomba de tiempo: el día que reconstruyas por una urgencia, puede que ya no sea el mismo sistema.

Así que además de parchear lo vulnerable, aproveché para fijar todo exactamente a lo que ya corría en producción, cambiando únicamente lo que tenía un aviso. Un parche de seguridad debería ser eso: un parche, no una mudanza.

Cómo lo hice, proyecto por proyecto

El método fue el mismo para cada aplicación, y es el que te recomendaría si estás en una situación parecida:

  1. Correr las pruebas antes de tocar nada. Si hay pruebas automáticas, necesitas saber que pasan antes; si no, no sabrás si fuiste tú quien rompió algo.
  2. Subir las versiones y volver a probar. Y probar de verdad: en los proyectos sin pruebas armé una imagen temporal, generé un PDF, convertí un documento, exporté un Excel y revisé que la aplicación arrancara.
  3. Respaldar la base de datos antes de desplegar. Siempre, aunque el cambio parezca inofensivo.
  4. Desplegar y verificar con los ojos abiertos. Que el contenedor quede sano, que el sitio responda, que los logs no tengan errores y que las tareas programadas sigan corriendo.

Y funcionó… con una sorpresa. En uno de los proyectos, al subir Flask, seis pruebas que antes pasaban empezaron a fallar. La causa era sutil: la nueva versión cierra los archivos subidos apenas termina la petición, y mi pantalla de carga con barra de progreso los leía después, mientras iba mostrando el avance. Resultado: "archivo cerrado". En producción habría significado que dos pantallas de carga dejaran de funcionar de un día para otro, sin ningún aviso de seguridad de por medio.

Lo arreglé copiando el archivo a memoria antes de empezar a mostrar el progreso. Pero la lección es la que importa: un parche de seguridad también puede romper cosas, y la única forma de enterarte antes que tus usuarios es tener pruebas y correrlas.

Por último, lo que no se ve: el servidor

Faltaba la parte que muchas veces se olvida porque no vive en tu código: el servidor mismo. Tenía 27 paquetes del sistema pendientes de actualizar, entre ellos el motor de contenedores, y un reinicio atrasado desde hacía semanas, porque el sistema ya tenía instalado un núcleo nuevo pero seguía corriendo con el viejo.

Lo hice al final, con respaldos frescos de todas las bases de datos, y con la tranquilidad de que cada contenedor estaba configurado para levantarse solo. Tras el reinicio revisé uno por uno: contenedores sanos, sitios respondiendo, certificados vigentes, tareas programadas intactas. Unos minutos de indisponibilidad a cambio de quedar al día.

Lo que me llevo

  • Revisa lo que realmente tienes, no lo que crees tener. Lo instalado y lo escrito en el archivo pueden ser cosas distintas.
  • Saber qué no te afecta es tan valioso como saber qué sí.
  • Fija tus versiones, todas. Que lo que probaste hoy sea exactamente lo que corra mañana.
  • Respalda antes, verifica después. Y sé honesto con lo que no pudiste probar: yo no pude abrir cada informe real de cada sistema, y por eso lo siguiente es recorrerlos con calma.
  • Una vulnerabilidad es una oportunidad de poner la casa en orden, no solo un susto del que hay que salir rápido.

¿Te ha pasado que una alerta de seguridad te agarra sin saber qué tienes?

Si te sonó familiar —o si sospechas que tu sitio, tu sistema o tu aplicación lleva meses sin que nadie los toque—, cuéntame. No hace falta que llegues con un diagnóstico técnico: con que me digas qué tienes, dónde corre y cuánto tiempo lleva sin actualizarse, alcanza para empezar a ver qué tan expuesto estás y por dónde conviene arrancar.

Marco Cubaque

Marco Cubaque

Ingeniero de software · DBA

Ingeniero de software y DBA con 5 años de experiencia moviéndose entre el desarrollo y la administración de bases de datos, automatizando los procesos manuales que antes dependían de que alguien no se cansara, no se equivocara o no se fuera. Hoy trabaja con Fiduprevisora automatizando tesorería y contabilidad; antes construyó el sistema de reclutamiento y la herramienta de seguimiento de proyectos de AGS Americas.

¿Qué te pareció este post?

5.0 ★ · 2 calificaciones