Saltar al contenido
← Volver al blog
3 min es

Vigilar el catálogo KEV de CISA sin tener un servidor encendido

kev-digest comprueba el catálogo CISA KEV cada tres horas, detecta que ha cambiado y publica el resultado, todo sobre GitHub Actions y sin una sola dependencia externa. Cómo está montado y por qué el guardián anti-encogimiento es la parte que de verdad importa.

  • cisa-kev
  • vulnerabilidades
  • github-actions
  • automatizacion
  • python
  • blue-team
Vigilar el catálogo KEV de CISA sin tener un servidor encendido

El catálogo KEV (Known Exploited Vulnerabilities) de CISA es de las pocas fuentes que responden a la pregunta que de verdad ordena una cola de parcheo: de todo lo publicado, que se está explotando ahora mismo. Ya escribí sobre por qué cruzarlo con NVD y EPSS cambia por completo el orden de prioridad. Lo que me faltaba era dejar de mirarlo a mano.

El diseño: sin dependencias, sin servidor

kev-digest es un script de Python que usa solo librería estándar (urllib, json, hashlib, pathlib) y corre cada tres horas en un cron de GitHub Actions. No hay base de datos: el estado completo vive en un archivo seen_cves.json versionado en el propio repositorio. Cada cambio real (entrada nueva, campo modificado, plazo que entra en la ventana de siete días, o el caso que más me interesa: una CVE que llevaba meses en el catálogo y de repente pasa a tener uso confirmado en ransomware) se añade al archivo del día en digest/ y genera un commit. Si no hay novedades, no se escribe nada: con ocho pasadas al día, escribir siempre llenaría el historial de commits vacíos.

El guardián anti-encogimiento

La parte que de verdad me preocupaba no era detectar cambios, era no destruir el historial por un fallo de red. Si el catálogo llega vacío o con un diez por ciento menos de entradas que la última vez, el script aborta sin guardar nada. Una descarga a medias marcaría cientos de CVEs como retiradas y grabaría esa foto como buena, borrando la línea base de un plumazo. Cuando el encogimiento es real (CISA sí retira entradas de vez en cuando), se lanza a mano con --force. Es la misma lógica que aplicaría a cualquier pipeline que escribe estado persistente: mejor no escribir nada que escribir algo corrupto con confianza.

Enriquecimiento sin volverse caro

Que algo esté en KEV dice que se explota, no si es un 9.8 o un 5.4. Las entradas nuevas se enriquecen con EPSS (probabilidad de explotación en 30 días, consulta en bloque) y NVD (CVSS y severidad, con cache en disco porque tiene rate-limit). Solo las entradas nuevas: pedir el CVSS de las más de mil seiscientas que ya están en seguimiento en cada pasada no aportaría nada y agotaría la cuota.

Dónde acaba el dato

data/latest.json es la salida pública, con contrato de campos estable porque algo más lo consume: la sección KEV Watch de Blue Team Hub descarga ese JSON ya procesado cada tres horas y lo pinta. El cálculo del diff vive en un solo sitio a propósito: dos implementaciones del mismo diff en dos lenguajes acabarían discrepando, y esa discrepancia sería difícil de detectar hasta que alguien confiara en el número equivocado.

Ahora mismo el catálogo tiene más de 1.694 CVEs en seguimiento, 352 con uso confirmado en campañas de ransomware. Todo eso corre sin que yo tenga que acordarme de mirarlo, y sin un solo servidor que mantener.