Análisis posterior del incidente de Cloudflare del 18 de noviembre de 2025
(blog.cloudflare.com)- El 18 de noviembre de 2025 a las 11:20 (UTC), se interrumpió una función clave de entrega de tráfico de la red de Cloudflare, por lo que usuarios de todo el mundo vieron páginas de error
- La causa fue que el “archivo de features” del sistema de Bot Management creció de forma anormal debido a un cambio de permisos en la base de datos; no estuvo relacionado con un ciberataque
- Debido a este aumento de tamaño, el software de enrutamiento de tráfico superó su límite y falló, provocando errores HTTP 5xx a gran escala
- Cerca de las 14:30 se detuvo la distribución del archivo problemático y se reemplazó por una versión estable anterior, con lo que se restauró el tráfico principal; todos los servicios volvieron a la normalidad a las 17:06
- Cloudflare calificó este incidente como su peor interrupción desde 2019 y está impulsando medidas para evitar recurrencias, como reforzar la validación de archivos de configuración e introducir un interruptor de apagado global
Resumen del incidente
- Alrededor de las 11:20, la red de Cloudflare sufrió una falla en la entrega del tráfico principal, y los usuarios vieron páginas internas de error de Cloudflare
- La causa no fue un ciberataque ni una acción maliciosa; el detonante directo fue un cambio de permisos en el sistema de base de datos
- Ese cambio hizo que el “archivo de features” usado por el sistema de Bot Management duplicara su tamaño, y luego se distribuyera por toda la red
- Mientras el software de enrutamiento de tráfico leía ese archivo, se excedió el límite de tamaño permitido, provocando errores del sistema
- Al principio se confundió con un ataque DDoS a gran escala, pero tras identificar la causa, se reemplazó por el archivo estable anterior para iniciar la recuperación
Desarrollo e impacto del incidente
- Antes de las 11:20, la tasa de errores 5xx estaba en niveles normales, pero después se disparó por la distribución del archivo de features incorrecto
- En algunos nodos del clúster de base de datos ClickHouse, se generaron resultados de consulta incorrectos cada 5 minutos, por lo que se distribuían de forma alternada archivos correctos e incorrectos, haciendo que el sistema entrara repetidamente en ciclos de recuperación y falla
- A partir de las 14:30 se detuvo la generación del archivo problemático y se insertó manualmente un archivo correcto, restaurando el servicio tras reiniciar el proxy central
- A las 17:06, todos los servicios volvieron a la normalidad
| Servicio | Impacto |
|---|---|
| Core CDN y servicios de seguridad | Errores HTTP 5xx |
| Turnstile | Fallas de carga, imposibilidad de iniciar sesión |
| Workers KV | Aumento brusco de errores 5xx por falla del gateway |
| Dashboard | Imposibilidad de iniciar sesión por la caída de Turnstile |
| Email Security | Caída temporal en la precisión de detección de spam, fallas en algunos movimientos automáticos |
| Access | Múltiples fallas de autenticación; las sesiones existentes se mantuvieron |
- Durante el incidente, aumentó la latencia de respuesta del CDN, debido al fuerte incremento en el uso de CPU del sistema de depuración
Causa del incidente: sistema de Bot Management
- El módulo de Bot Management de Cloudflare usa modelos de machine learning para generar una puntuación de bot por solicitud
- El archivo de configuración de features usado como entrada del modelo se distribuye a toda la red cada pocos minutos para responder a las amenazas más recientes
- Debido a un cambio en el comportamiento de las consultas de ClickHouse, se incluyeron muchas filas de features duplicadas, aumentando el tamaño del archivo
- Como resultado, el módulo de Bot Management falló y devolvió respuestas HTTP 5xx, afectando también a Workers KV y Access
- En el nuevo motor de proxy FL2 se produjeron errores 5xx, mientras que en la versión anterior FL la puntuación de bot se fijó en 0, aumentando los falsos positivos
Cambio en el comportamiento de las consultas de ClickHouse
- A las 11:05 se desplegó un cambio en los permisos de acceso a la base de datos de ClickHouse
- Antes, solo era posible consultar metadatos de la base de datos
default, pero tras el cambio también quedaron expuestos los metadatos de la base de datosr0 - La consulta que generaba el archivo de features de Bot Management se ejecutó sin filtrar por nombre de base de datos, por lo que devolvió columnas duplicadas
- Esto hizo que el número de filas del archivo de features se duplicara con creces, superando los límites del sistema
Preasignación de memoria y pánico del sistema
- El módulo de Bot Management preasigna memoria con un límite máximo de 200 features de machine learning
- Como el archivo incorrecto incluía más de 200 features, se produjo un panic en código Rust, con la salida:
thread fl2_worker_thread panicked: called Result::unwrap() on an Err value - Esto provocó una gran cantidad de errores HTTP 5xx
Otros impactos y proceso de recuperación
- Workers KV y Access dependían del proxy central, lo que amplificó el impacto del incidente
- A las 13:04 se aplicó un parche para que Workers KV evitara el proxy, reduciendo la tasa de errores
- Dashboard no permitía iniciar sesión debido a su dependencia de Turnstile y Workers KV
- Hubo dos periodos de baja disponibilidad: 11:30–13:10 y 14:40–15:30
- La acumulación de pendientes y las solicitudes reintentadas aumentaron la latencia, y la recuperación llegó alrededor de las 15:30
- Después de las 14:30, la mayoría de los servicios se normalizaron, y la recuperación completa se logró a las 17:06
Medidas para evitar recurrencias
- Reforzar la validación de entradas en los archivos de configuración generados por Cloudflare
- Ampliar los interruptores globales de desactivación (kill switch)
- Evitar el agotamiento de recursos del sistema causado por el reporte de errores
- Revisar las condiciones de error en todos los módulos del proxy central
Resumen de la línea de tiempo (UTC)
| Hora | Estado | Descripción |
|---|---|---|
| 11:05 | Normal | Se despliega el cambio de control de acceso a la base de datos |
| 11:28 | Inicio del impacto | Se detectan los primeros errores en el tráfico de clientes |
| 11:32–13:05 | Investigación en curso | Análisis de la causa de los errores en Workers KV e intentos de mitigación |
| 13:05 | Impacto reducido | Se aplica bypass para Workers KV y Access |
| 13:37 | Recuperación intensiva | Preparación del rollback del archivo de configuración de Bot Management |
| 14:24 | Se detiene la distribución del archivo problemático | Finalizan las pruebas del archivo correcto |
| 14:30 | Se resuelve el impacto principal | Distribución global del archivo correcto e inicio de la recuperación del servicio |
| 17:06 | Recuperación total | Todos los servicios vuelven a la normalidad |
Conclusión
- Este incidente fue provocado por la interacción entre la lógica de generación del archivo de configuración de Bot Management y un cambio en los permisos de la base de datos
- Cloudflare lo evalúa como la interrupción de red más grave desde 2019
- A futuro, impulsará mejoras estructurales para reforzar la resiliencia del sistema y fortalecer los mecanismos de defensa automatizados
8 comentarios
Las fallas relacionadas con archivos de configuración ocurren en todas partes.
Como Cloudflare no funcionaba y todo tipo de servicios se interrumpieron, fue un infierno..
Parece que publicaron el documento de análisis de la causa bastante rápido, wow.
Por cierto, parece que quien escribió este artículo era el CEO.
Opiniones en Hacker News
Esta es una historia de incidente de .unwrap() de varios millones de dólares
Llamar a
.unwrap()en una ruta de infraestructura crítica de internet equivale a declarar: “esto jamás va a fallar; si falla, matamos el hilo de inmediato”El compilador de Rust obliga a expresar explícitamente la posibilidad de fallo, pero aquí eligieron el pánico en lugar de manejarlo con elegancia
Me parece un caso típico del antipatrón "parse, don’t validate"
.unwrap(). Tal vez porque aparece mucho en código de ejemploEn código real de producción,
.unwrap()y.expect()deberían revisarse como si fueran pánicosSi vas a usar
.unwrap()en producción, deberías exigir un comentario de “INFALLIBILITY”, y eso puede forzarse conclippy::unwrap_usedNo fue solo por
.unwrap(), sino porque la consulta no separaba las bases de datos, eso agrandó el payload, y ClickHouse expuso más DBMás que concluir “fue por unwrap”, me parece más importante mejorar el diseño para que no se necesite un interruptor global de apagado o para evitar que se saturen los recursos del sistema
En la capa FL2 deberían atraparse los pánicos de cada componente, pero fail-open no siempre es mejor
Habría que agregar lógica para decidir explícitamente en el nivel FL2 si un pánico debe capturarse y manejarse o no
Si es un sistema con sharding, también me pregunto por qué no hubo un rollout gradual con monitoreo
!y unwrap explícito con?Yo casi nunca uso el implícito. Incluso cuando el valor está garantizado, siempre lo manejo explícitamente
Por ejemplo, defino
@IBOutlet weak var someView?en vez de@IBOutlet weak var someView!Es una especie de enfoque de belt & suspenders
Es realmente impresionante que hayan publicado el post mortem menos de 24 horas después de la caída
En la mayoría de las grandes empresas, con revisión de varios stakeholders, sería casi imposible publicar algo de este nivel
Al leer la explicación de la caída de Cloudflare, me pregunté: “¿por qué tardaron tanto en recuperarse?”
Entendí la causa de la caída, pero si la mayor parte de la red estaba fuera de servicio, pensé que revertir el cambio de configuración más reciente debería haber sido la prioridad número uno
Claro, en retrospectiva es fácil verlo, pero impresiona que empezaran la investigación en solo 7 minutos
Este incidente se siente parecido al caso de CrowdStrike
Un archivo de configuración generado automáticamente rompió el software y se propagó por toda la red
Entiendo la necesidad de desplegar rápido, pero esto deja en evidencia la falta de una estrategia de rollout gradual y rollback
Si uno mira el plan de mejoras futuras que anunció Cloudflare, incluye:
Pero falta despliegue canario o despliegue gradual de configuración
Un interruptor global puede ser riesgoso, y un solo bug podría detener todo el sistema
También me pregunto por qué usaron ClickHouse como almacén de feature flags. Incluso la documentación de deduplicación de ClickHouse menciona riesgos
Si hubiera mapeo de dependencias entre servicios, rastrear la causa habría sido mucho más fácil
Los despliegues de código se hacen con cuidado, pero los de configuración no. Hace falta asumir que la configuración también es código
Me pareció interesante la parte de que la página de estado cayó y por eso al principio pensaron que era un ataque
Dicen que está completamente separada de la infraestructura de Cloudflare, pero no explican por qué cayó también
Yo integré Turnstile con una estrategia fail-open, y en esta caída me sirvió
Si no carga el JS, permito enviar con un token dummy, y si la validación falla en el backend, también lo trato como fail-open
Algunos usuarios igual quedaron bloqueados, pero el impacto general se redujo
Es un enfoque posible porque tengo otras medidas de mitigación de bots
Pero eso parece funcionar solo cuando no se trata de un ataque dirigido
Me pregunto por qué permitieron
.unwrap()en código de CloudflareComo mínimo deberían haber usado
expect("esto jamás debería pasar")La filosofía de tratar los errores como valores existe justo para prevenir este tipo de problema, y además habría facilitado muchísimo el diagnóstico
En código con llamadas de red hay demasiadas posibilidades de fallo
Durante el desarrollo uso
.unwrap(), pero en producción a veces dejo expect() cuando realmente no hay forma de continuarLa verdadera lección es que demasiadas funciones dependen de unos pocos jugadores
La lógica de que el ganador se lleva todo está profundizándose y eso reduce la resiliencia del sistema
Claro, llegaron a esa posición por mérito, pero esperar que internet siempre vaya a “funcionar normalmente” ya parece demasiado
Decir “si es Rust, entonces todo es seguro” es una exageración
En cualquier lenguaje, si lo usas mal es como apuntarte al pie con un arma
Hasta una empresa del nivel de CF usa
.unwrap(), wow. ¿Cómo terminó ese código en producción?No parece que
unwrapsea el problema.El problema de fondo es una consulta incorrecta.
Pero también creo que fue un problema haberse saltado la validación del problema usando
unwrap.Aunque hubiera surgido un problema internamente, si se hubiera manejado el error, el tráfico no se habría caído.