23 puntos por GN⁺ 2025-11-19 | 8 comentarios | Compartir por WhatsApp
  • 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 datos r0
  • 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

 
t7vonn 2025-11-19

Las fallas relacionadas con archivos de configuración ocurren en todas partes.

 
princox 2025-11-19

Como Cloudflare no funcionaba y todo tipo de servicios se interrumpieron, fue un infierno..

 
epdlemflaj 2025-11-19

Parece que publicaron el documento de análisis de la causa bastante rápido, wow.

 
epdlemflaj 2025-11-19

Por cierto, parece que quien escribió este artículo era el CEO.

 
GN⁺ 2025-11-19
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"

    • Mucha gente parece tener un punto ciego con .unwrap(). Tal vez porque aparece mucho en código de ejemplo
      En código real de producción, .unwrap() y .expect() deberían revisarse como si fueran pánicos
      Si vas a usar .unwrap() en producción, deberías exigir un comentario de “INFALLIBILITY”, y eso puede forzarse con clippy::unwrap_used
    • El punto de este texto parece ser que el problema surge más por la combinación de componentes normales que por una sola causa
      No fue solo por .unwrap(), sino porque la consulta no separaba las bases de datos, eso agrandó el payload, y ClickHouse expuso más DB
      Má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 realidad esto también falló fuera de la ruta de Rust. El sistema de gestión de bots clasificó todo el tráfico como bots
      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 lo hubieran manejado con elegancia, probablemente habría habido degradación de rendimiento (aunque aun así me parece mejor que perder confiabilidad)
      Si es un sistema con sharding, también me pregunto por qué no hubo un rollout gradual con monitoreo
    • Swift tiene unwrap implícito con ! 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

    • Me da curiosidad qué políticas internas les permiten publicar algo así con tanta rapidez y transparencia
      En la mayoría de las grandes empresas, con revisión de varios stakeholders, sería casi imposible publicar algo de este nivel
    • Además, el texto está muy bien escrito. Comparado con los post mortems de AWS, casi parece literatura
  • 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

    • Al principio lo confundieron con un ataque. Después entendieron el problema, pero no había forma de reemplazar en cola el archivo corrupto, y tuvieron que reiniciar una enorme cantidad de máquinas por todo el mundo
  • 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

    • Más que un despliegue de CI/CD, esto se entiende mejor como el canal de control de un sistema distribuido de detección de bots
    • Sorprende que lo empujaran directo a producción sin un simulador
    • Aun así, quiero creer que esto servirá para que mejoren
  • Si uno mira el plan de mejoras futuras que anunció Cloudflare, incluye:

    • Refuerzo de la validación de archivos de configuración generados por Cloudflare
    • Agregar un interruptor global de apagado
    • Prevención del agotamiento de recursos por core dumps o reportes de error
    • Revisión de los modos de error de los módulos proxy
      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
    • La configuración de gestión de bots sí necesita propagarse rápido, pero si la hubieran probado primero en una instancia, habrían detectado el pánico antes
      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
    • El servicio de configuración sí tenía rollout gradual, pero los servicios consumidores se actualizaban automáticamente con demasiada frecuencia, así que hasta un pequeño porcentaje de errores terminó afectando a todo el sistema
    • La configuración global es útil para responder rápido, pero es indispensable tener un mecanismo de rollback rápido
      Si hubiera mapeo de dependencias entre servicios, rastrear la causa habría sido mucho más fácil
    • Al final, la mayoría de las grandes caídas son por config push
      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

    • Lo más probable es que haya sido un fallo de escalado de infraestructura por un aumento repentino de tráfico
    • En la práctica quizás pensaban que no había dependencia con Cloudflare, pero como gran parte de internet depende de CloudFront, tal vez no era completamente independiente
    • Para saber la causa haría falta un post mortem de statuspage.io. Es un servicio operado por Atlassian
    • También puede ser simplemente que el tamaño de Cloudflare haya hecho que se concentrara demasiado tráfico
  • 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

    • Entonces surge la duda de si un atacante podría bloquear el script y saltarse el CAPTCHA
      Pero eso parece funcionar solo cuando no se trata de un ataque dirigido
  • Me pregunto por qué permitieron .unwrap() en código de Cloudflare
    Como 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

    • No trabajo en Cloudflare, pero sí uso mucho Rust
      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 continuar
  • La 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

 
barca105 2025-11-19

Hasta una empresa del nivel de CF usa .unwrap(), wow. ¿Cómo terminó ese código en producción?

 
skageektp 2025-11-19

No parece que unwrap sea el problema.

 
barca105 2025-11-19

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.