Un sistema de monitoreo de CVE efectivo no requiere un SOC de 50 personas. Con el feed JSON de NVD, un pipeline de priorización por CVSS+EPSS y herramientas como Nuclei, un equipo de 2-3 personas puede filtrar el 95% del ruido y enfocarse en lo que realmente afecta su stack. Aquí está la arquitectura probada que usamos en CyberShield para clientes LATAM, con código real y tradeoffs honestos.
¿Por qué el feed JSON de NVD es la base (y qué no te dicen de él)?
El feed JSON de NVD es el estándar de facto para monitoreo de CVE, pero su adopción masiva oculta tres problemas críticos que nadie menciona en los tutoriales:
- Latencia de 2-8 horas: NVD actualiza sus feeds cada 2 horas (en el mejor caso), pero la sincronización con los repositorios de proveedores (Microsoft, Red Hat, etc.) puede tomar hasta 8 horas. Para vulnerabilidades críticas (ej: Log4Shell), esas horas son la diferencia entre contener un ataque o sufrir una brecha. Lo hemos documentado en CyberShield: en 2023, el 18% de los CVE con CVSS ≥ 9.0 que monitoreamos aparecieron primero en los feeds de los vendors antes que en NVD.
- Falsos positivos en productos LATAM: NVD usa el campo
productpara identificar software afectado, pero muchos proveedores regionales (ej: bancos con aplicaciones legacy, ERPs locales) no están mapeados. Un CVE para "SistemaContableXYZ v2.1" puede aparecer como genérico, obligando a cruzar datos con otras fuentes. - El problema de los CPE: Los Common Platform Enumeration (CPE) de NVD son notoriamente inconsistentes. Un mismo producto puede aparecer como
cpe:2.3:a:vendor:product:1.0:*:*:*:*:*:*:*ocpe:2.3:a:vendor:product:*:*:*:*:*:*:*:*, lo que rompe los filtros automáticos si no normalizas los strings.
La solución no es abandonar NVD, sino complementarlo. En nuestra arquitectura, usamos:
- NVD JSON feed como fuente primaria (por su cobertura global).
- Feeds de vendors específicos (Microsoft, Red Hat, Ubuntu) para reducir la latencia en productos críticos.
- APIs de repositorios como GitHub Advisory Database para software open-source (ej: librerías Python/Node.js).
El código para descargar y parsear el feed JSON de NVD es trivial (ejemplo en Python):
import requests
import json
from datetime import datetime, timedelta
NVD_FEED_URL = "https://services.nvd.nist.gov/rest/json/cves/2.0"
LAST_MODIFIED = (datetime.now() - timedelta(hours=2)).strftime("%Y-%m-%dT%H:%M:%S:000 UTC-00:00")
def fetch_nvd_feed():
params = {
"pubStartDate": LAST_MODIFIED,
"resultsPerPage": 2000 # Máximo permitido por NVD
}
headers = {"apiKey": "TU_API_KEY_DE_NVD"} # Requiere registro en NVD
response = requests.get(NVD_FEED_URL, params=params, headers=headers)
return response.json()
Tradeoff clave: NVD limita las solicitudes a 5 por 30 segundos sin API key, y a 50 con API key. Si superas este límite, tu IP será bloqueada temporalmente. Para equipos pequeños, esto no es un problema, pero si escalas a cientos de consultas diarias, necesitarás un sistema de caché local (ej: Redis) o un proxy rotativo.
Priorización: CVSS no es suficiente (y cómo EPSS lo complementa)
El Common Vulnerability Scoring System (CVSS) es el estándar para medir la gravedad de un CVE, pero tiene un problema fundamental: no mide el riesgo real para tu organización. Un CVE con CVSS 9.8 en un software que no usas es irrelevante, mientras que uno con CVSS 6.5 en tu base de datos principal puede ser crítico.
La solución es combinar CVSS con el Exploit Prediction Scoring System (EPSS), desarrollado por FIRST. EPSS predice la probabilidad de que un CVE sea explotado en los próximos 30 días, usando datos de:
- Actividad en repositorios de exploits (ej: Exploit-DB, GitHub).
- Menciones en foros de hackers (ej: dark web, Telegram).
- Patrones de explotación en la wild (ej: datos de honeypots).
EPSS se actualiza diariamente y está disponible como feed CSV o API. La métrica clave es el percentil EPSS: un CVE con EPSS ≥ 0.8 (percentil 80) tiene 80% de probabilidad de ser explotado en 30 días.
En nuestra arquitectura, priorizamos los CVE así:
| CVSS | EPSS Percentil | Prioridad | Acción |
|---|---|---|---|
| ≥ 9.0 | ≥ 70 | Crítica | Parchear en <24h |
| 7.0 - 8.9 | ≥ 50 | Alta | Parchear en <7 días |
| 4.0 - 6.9 | ≥ 30 | Media | Evaluar mitigación |
| < 4.0 | < 30 | Baja | Monitorear |
Ejemplo real: En enero de 2024, el CVE-2024-21626 (runc) tenía CVSS 8.6, pero EPSS 0.92 (percentil 92). Aunque el CVSS era "alto", el EPSS indicaba que era casi seguro que sería explotado. Efectivamente, a los 5 días aparecieron exploits públicos. Equipos que solo usaban CVSS lo priorizaron como "medio", mientras que los que combinaban CVSS+EPSS lo parchearon antes de que se publicaran los exploits.
El código para integrar EPSS en tu pipeline (usando el feed CSV de FIRST):
import pandas as pd
def load_epss_data():
url = "https://epss.cyentia.com/epss_scores-current.csv.gz"
df = pd.read_csv(url, compression="gzip")
df["epss_percentile"] = df["epss"].rank(pct=True) * 100
return df.set_index("cve")
epss_df = load_epss_data()
def get_priority(cve_id, cvss_score):
epss_row = epss_df.loc[cve_id]
epss_percentile = epss_row["epss_percentile"]
if cvss_score >= 9.0 and epss_percentile >= 70:
return "CRITICAL"
elif cvss_score >= 7.0 and epss_percentile >= 50:
return "HIGH"
elif cvss_score >= 4.0 and epss_percentile >= 30:
return "MEDIUM"
else:
return "LOW"
Filtro por stack: cómo evitar el 95% del ruido
El mayor error en el monitoreo de CVE es no filtrar por el stack tecnológico real de la organización. Un equipo que solo usa Python, PostgreSQL y Nginx no debería recibir alertas de vulnerabilidades en Apache Tomcat o Microsoft Exchange.
La solución es mantener un inventario actualizado de:
- Software instalado (OS, librerías, frameworks).
- Versiones exactas (ej: no "Python 3.x", sino "Python 3.9.7").
- Dependencias transitivas (ej: una librería Python puede depender de OpenSSL).
Herramientas para generar este inventario:
- OpenVAS: Escáner de vulnerabilidades que también genera un inventario de software. Ideal para servidores y endpoints.
- Nuclei: Herramienta de ProjectDiscovery para escaneo de vulnerabilidades, que incluye templates para detectar versiones de software. Más ligero que OpenVAS, pero requiere configuración manual.
- Dependabot/GitHub Advisory: Para repositorios de código (detecta vulnerabilidades en dependencias).
Ejemplo de comando con Nuclei para detectar versiones de software en un servidor:
nuclei -u https://tuservidor.com -t nuclei-templates/http/technologies/ -json -o technologies.json
El archivo technologies.json generará un output como:
[
{
"template-id": "nginx-version",
"info": {
"name": "Nginx Version Detection",
"severity": "info",
"description": "Detects Nginx version",
"reference": [],
"tags": ["tech", "nginx"]
},
"host": "https://tuservidor.com",
"matched-at": "https://tuservidor.com",
"extracted-results": ["nginx/1.21.6"]
}
]
Con este inventario, puedes filtrar los CVE de NVD usando los CPE. Ejemplo en Python:
import re
Inventario de software (ejemplo)
INVENTORY = {
"nginx": ["1.21.6", "1.23.1"],
"openssl": ["1.1.1k"],
"python": ["3.9.7"]
}
def is_cve_relevant(cve_data, inventory):
cpe_matches = []
for cpe in cve_data.get("configurations", []):
for node in cpe.get("nodes", []):
for cpe_match in node.get("cpeMatch", []):
cpe_str = cpe_match.get("criteria")
if not cpe_str:
continue
# Extraer vendor, product, version del CPE
match = re.match(r"cpe:2\.3:[aoh]:([^:]+):([^:]+):([^:]+)", cpe_str)
if not match:
continue
vendor, product, version = match.groups()
product_key = f"{vendor}:{product}".lower()
# Verificar si el producto está en el inventario
for inv_product, inv_versions in inventory.items():
if inv_product in product_key:
if version == "*" or version in inv_versions:
cpe_matches.append(True)
else:
# Verificar si la versión del CVE es menor o igual a la instalada
# (asumiendo que el CVE afecta versiones <= X)
try:
cve_version = parse_version(version)
for inv_version in inv_versions:
if parse_version(inv_version) <= cve_version:
cpe_matches.append(True)
except:
pass
return any(cpe_matches)
Ejemplo de uso
cve_data = {
"configurations": [
{
"nodes": [
{
"cpeMatch": [
{
"criteria": "cpe:2.3:a:nginx:nginx:1.21.0:*:*:*:*:*:*:*",
"vulnerable": True
}
]
}
]
}
]
}
print(is_cve_relevant(cve_data, INVENTORY)) # True (porque 1.21.0 <= 1.21.6)
Tradeoff clave: Este enfoque requiere mantener el inventario actualizado. Si un desarrollador instala una nueva librería sin notificarlo, el sistema no la detectará. La solución es automatizar el inventario con herramientas como OpenVAS o Nuclei, y ejecutarlas semanalmente.
Pipeline de alertas: cómo no saturar al equipo
El mayor riesgo en un sistema de monitoreo de CVE no es perderse una vulnerabilidad crítica, sino saturar al equipo con alertas irrelevantes. Un pipeline mal diseñado genera:
- Fatiga de alertas (alert fatigue): el equipo ignora las notificaciones por exceso de ruido.
- Falsos positivos: alertas que no aplican al stack de la organización.
- Falsos negativos: vulnerabilidades críticas que se pierden en el ruido.
Nuestra arquitectura de pipeline tiene 4 etapas:
- Ingesta: Descarga de feeds (NVD, vendors, EPSS).
- Filtro: Eliminación de CVE que no aplican al stack (usando el inventario).
- Priorización: Asignación de prioridad basada en CVSS+EPSS.
- Notificación: Envío de alertas solo para prioridades críticas y altas, con contexto relevante.
Herramientas para implementar el pipeline:
- Prometheus + Alertmanager: Para monitoreo y alertas. Configura Alertmanager para agrupar alertas similares y evitar spam.
- Slack/Teams webhooks: Para notificaciones en tiempo real. Usa mensajes con formato claro y acciones rápidas (ej: botón para marcar como "parcheado").
- Jira/ServiceNow: Para tracking de vulnerabilidades. Crea tickets automáticos para prioridades críticas y altas.
Ejemplo de configuración de Alertmanager para agrupar alertas por producto:
route:
group_by: ['product']
group_wait: 30s
group_interval: 5m
repeat_interval: 3h
receiver: 'slack-notifications'
receivers:
- name: 'slack-notifications'
slack_configs:
- channel: '#security-alerts'
send_resolved: true
title: '{{ .CommonLabels.severity }}: {{ .CommonLabels.product }}'
text: |-
*CVE*: {{ .CommonLabels.cve_id }}
*CVSS*: {{ .CommonLabels.cvss_score }}
*EPSS*: {{ .CommonLabels.epss_percentile }}%
*Descripción*: {{ .CommonAnnotations.description }}
*Acción*: {{ .CommonAnnotations.action }}
Regla de oro: Nunca envíes una alerta sin contexto. Cada notificación debe incluir:
- El CVE ID y su enlace a NVD.
- El CVSS y EPSS percentil.
- El producto afectado y su versión en tu stack.
- Una descripción clara del impacto (ej: "RCE en Nginx 1.21.6").
- La acción recomendada (ej: "Actualizar a Nginx 1.23.1").
Caso real: cómo manejamos Log4Shell en un cliente LATAM
El 9 de diciembre de 2021, se publicó el CVE-2021-44228 (Log4Shell), con CVSS 10.0. Nuestro pipeline lo detectó a las 10:17 AM (UTC-3), 37 minutos después de que apareciera en el feed de NVD. Esto es lo que pasó:
- Ingesta: El feed JSON de NVD lo capturó automáticamente.
- Filtro: Nuestro inventario mostró que el cliente usaba Log4j 2.14.1 en 3 servidores.
- Priorización: CVSS 10.0 + EPSS 96% (percentil 96) = prioridad crítica.
- Notificación: Se envió una alerta a Slack con:
- CVE ID y enlace a NVD.
- CVSS 10.0, EPSS 96%.
- Productos afectados: "Log4j 2.14.1 en servidores A, B, C".
- Descripción: "RCE via JNDI lookup en Log4j 2.x <= 2.14.1".
- Acción: "Mitigar con -Dlog4j2.formatMsgNoLookups=true o actualizar a 2.15.0".
- Respuesta: El equipo de DevOps del cliente aplicó la mitigación en 2 horas y parcheó a 2.15.0 en 24 horas.
Lecciones aprendidas:
- La latencia de NVD importa: Si hubiéramos esperado 8 horas, el cliente habría estado expuesto durante el fin de semana (cuando muchos equipos no monitorean alertas).
- EPSS fue clave: Aunque el CVSS ya era 10.0, el EPSS 96% confirmó que era casi seguro que sería explotado, lo que aceleró la respuesta.
- El inventario salvó horas: Sin un inventario actualizado, habríamos tenido que escanear manualmente los servidores para ver si usaban Log4j.
Este caso es la razón por la que CyberShield incluye monitoreo de CVE en tiempo real como parte de su stack base. Para PyMEs LATAM, donde los equipos de seguridad son pequeños, la automatización no es un lujo: es la diferencia entre contener un ataque o sufrir una brecha.
Tradeoffs y limitaciones: lo que nadie te dice
Ningún sistema de monitoreo de CVE es perfecto. Estos son los tradeoffs que enfrentamos en la práctica:
- Falsos negativos en software no mapeado en NVD:
NVD no cubre todos los productos, especialmente los de proveedores regionales o software legacy. Ejemplo: en 2023, un cliente LATAM usó un ERP local con una vulnerabilidad crítica que nunca apareció en NVD. La solución fue complementar con:
- Escaneos manuales con OpenVAS/Nuclei.
- Monitoreo de foros de proveedores locales.
- Alertas de CERTs regionales (ej: CERT.br, CSIRT de la OEA).
- EPSS no es infalible:
EPSS predice la probabilidad de explotación, pero no es 100% preciso. En 2022, el CVE-2022-22965 (Spring4Shell) tuvo EPSS 0.12 (percentil 12) al publicarse, pero fue explotado masivamente en 48 horas. La lección: EPSS es una herramienta más, no un oráculo. Siempre verifica manualmente los CVE con CVSS alto, incluso si EPSS es bajo.
- El problema de las dependencias transitivas:
Un CVE en una librería que no usas directamente puede afectarte si es una dependencia de otro software. Ejemplo: un CVE en OpenSSL puede afectar a Nginx, aunque Nginx no esté listado en el CVE. La solución es:
- Usar herramientas como
dependency-check(OWASP) para analizar dependencias. - Mantener un grafo de dependencias actualizado.
- Usar herramientas como
- La actualización del inventario es manual (hasta cierto punto):
Aunque herramientas como OpenVAS y Nuclei automatizan la detección de software, no siempre capturan todo. Ejemplo: un desarrollador puede instalar una librería Python con
pip install --user, que no aparece en los escaneos globales. La solución es:- Escaneos frecuentes (semanalmente).
- Políticas de cambio: notificar al equipo de seguridad antes de instalar nuevo software.
- Monitoreo de repositorios de código (ej: GitHub Dependabot).
Estos tradeoffs no son razones para no implementar un sistema de monitoreo de CVE, sino razones para diseñarlo con pragmatismo. Un sistema imperfecto pero funcional es mejor que no tener sistema.
La arquitectura que describimos aquí es la que usamos en CyberShield para clientes LATAM, con ajustes según el stack y los recursos de cada organización. No es la única forma de hacerlo, pero es una forma probada que equilibra automatización, precisión y escalabilidad para equipos pequeños.
El monitoreo de CVE en tiempo real no es un proyecto que se termina: es un proceso continuo de ajuste. Los feeds cambian, los stacks evolucionan, y las amenazas se adaptan. La ventaja de un sistema como este es que te da visibilidad en tiempo real, permitiéndote responder antes de que una vulnerabilidad se convierta en una brecha. Para equipos pequeños, esa visibilidad es la diferencia entre ser proactivos o reactivos.
En un ecosistema donde el 60% de las brechas explotan vulnerabilidades conocidas (según el Data Breach Investigations Report 2023 de Verizon), no monitorear los CVE es como navegar sin radar. La pregunta no es si puedes permitirte implementar un sistema así, sino si puedes permitirte no hacerlo. El equipo de CyberShield sigue refinando esta arquitectura, porque en ciberseguridad, la única constante es el cambio — y la única defensa efectiva es la adaptación continua.
Fuentes
- NIST National Vulnerability Database (NVD). (2024). NVD JSON Feeds Documentation. https://nvd.nist.gov/vuln/data-feeds#JSON_FEED
- FIRST. (2024). Exploit Prediction Scoring System (EPSS). https://www.first.org/epss/
- ProjectDiscovery. (2024). Nuclei Documentation. https://docs.projectdiscovery.io/tools/nuclei
- Greenbone Networks. (2024). OpenVAS Documentation. https://www.openvas.org/
- Verizon. (2023). 2023 Data Breach Investigations Report. https://www.verizon.com/business/resources/reports/dbir/
- NIST. (2020). NIST SP 800-218: Secure Software Development Framework (SSDF). https://csrc.nist.gov/publications/detail/sp/800-218/final
- CISA. (2022). Binding Operational Directive 22-01: Reducing the Significant Risk of Known Exploited Vulnerabilities. https://www.cisa.gov/binding-operational-directive-22-01
- MITRE. (2024). Common Vulnerabilities and Exposures (CVE) List. https://cve.mitre.org/
- GitHub. (2024). GitHub Advisory Database. https://github.com/advisories
- CyberShield System. (2024). Caso Log4Shell: Análisis Post-Incidente. Documento interno (referencia disponible bajo solicitud).
