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:

  1. 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.
  2. Falsos positivos en productos LATAM: NVD usa el campo product para 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.
  3. 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:*:*:*:*:*:*:* o cpe: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:

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:

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:

  1. Software instalado (OS, librerías, frameworks).
  2. Versiones exactas (ej: no "Python 3.x", sino "Python 3.9.7").
  3. Dependencias transitivas (ej: una librería Python puede depender de OpenSSL).

Herramientas para generar este inventario:

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:

Nuestra arquitectura de pipeline tiene 4 etapas:

  1. Ingesta: Descarga de feeds (NVD, vendors, EPSS).
  2. Filtro: Eliminación de CVE que no aplican al stack (usando el inventario).
  3. Priorización: Asignación de prioridad basada en CVSS+EPSS.
  4. Notificación: Envío de alertas solo para prioridades críticas y altas, con contexto relevante.

Herramientas para implementar el pipeline:

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:

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ó:

  1. Ingesta: El feed JSON de NVD lo capturó automáticamente.
  2. Filtro: Nuestro inventario mostró que el cliente usaba Log4j 2.14.1 en 3 servidores.
  3. Priorización: CVSS 10.0 + EPSS 96% (percentil 96) = prioridad crítica.
  4. 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".
  5. 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:

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:

  1. 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).
  2. 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.

  3. 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.
  4. 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

  1. NIST National Vulnerability Database (NVD). (2024). NVD JSON Feeds Documentation. https://nvd.nist.gov/vuln/data-feeds#JSON_FEED
  2. FIRST. (2024). Exploit Prediction Scoring System (EPSS). https://www.first.org/epss/
  3. ProjectDiscovery. (2024). Nuclei Documentation. https://docs.projectdiscovery.io/tools/nuclei
  4. Greenbone Networks. (2024). OpenVAS Documentation. https://www.openvas.org/
  5. Verizon. (2023). 2023 Data Breach Investigations Report. https://www.verizon.com/business/resources/reports/dbir/
  6. NIST. (2020). NIST SP 800-218: Secure Software Development Framework (SSDF). https://csrc.nist.gov/publications/detail/sp/800-218/final
  7. CISA. (2022). Binding Operational Directive 22-01: Reducing the Significant Risk of Known Exploited Vulnerabilities. https://www.cisa.gov/binding-operational-directive-22-01
  8. MITRE. (2024). Common Vulnerabilities and Exposures (CVE) List. https://cve.mitre.org/
  9. GitHub. (2024). GitHub Advisory Database. https://github.com/advisories
  10. CyberShield System. (2024). Caso Log4Shell: Análisis Post-Incidente. Documento interno (referencia disponible bajo solicitud).