Um sistema de monitoramento de CVE eficaz não requer um SOC com 50 pessoas. Com o feed JSON do NVD, um pipeline de priorização por CVSS+EPSS e ferramentas como Nuclei, uma equipe de 2 a 3 pessoas pode filtrar 95% do ruído e focar no que realmente afeta seu stack. Aqui está a arquitetura testada que usamos na CyberShield para clientes da América Latina, com código real e tradeoffs honestos.

Por que o feed JSON do NVD é a base (e o que não te contam sobre ele)?

O feed JSON do NVD é o padrão de fato para monitoramento de CVE, mas sua adoção massiva esconde três problemas críticos que ninguém menciona nos tutoriais:

  1. Latência de 2 a 8 horas: O NVD atualiza seus feeds a cada 2 horas (no melhor caso), mas a sincronização com os repositórios dos fornecedores (Microsoft, Red Hat, etc.) pode levar até 8 horas. Para vulnerabilidades críticas (ex.: Log4Shell), essas horas fazem a diferença entre conter um ataque ou sofrer uma violação. Documentamos isso na CyberShield: em 2023, 18% dos CVE com CVSS ≥ 9.0 que monitoramos apareceram primeiro nos feeds dos vendors antes do NVD.
  2. Falsos positivos em produtos da América Latina: O NVD usa o campo product para identificar software afetado, mas muitos fornecedores regionais (ex.: bancos com aplicações legadas, ERPs locais) não estão mapeados. Um CVE para "SistemaContabilXYZ v2.1" pode aparecer como genérico, obrigando a cruzar dados com outras fontes.
  3. O problema dos CPE: Os Common Platform Enumeration (CPE) do NVD são notoriamente inconsistentes. Um mesmo produto pode aparecer como cpe:2.3:a:vendor:product:1.0:*:*:*:*:*:*:* ou cpe:2.3:a:vendor:product:*:*:*:*:*:*:*:*, o que quebra os filtros automáticos se não normalizar as strings.

A solução não é abandonar o NVD, mas complementá-lo. Em nossa arquitetura, usamos:

O código para baixar e analisar o feed JSON do NVD é trivial (exemplo em 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 pelo NVD
    }
    headers = {"apiKey": "SUA_CHAVE_API_DO_NVD"}  # Requer registro no NVD
    response = requests.get(NVD_FEED_URL, params=params, headers=headers)
    return response.json()

Tradeoff chave: O NVD limita as solicitações a 5 a cada 30 segundos sem chave de API, e a 50 com chave de API. Se exceder esse limite, seu IP será bloqueado temporariamente. Para equipes pequenas, isso não é um problema, mas se escalar para centenas de consultas diárias, será necessário um sistema de cache local (ex.: Redis) ou um proxy rotativo.

Priorização: CVSS não é suficiente (e como o EPSS o complementa)

O Common Vulnerability Scoring System (CVSS) é o padrão para medir a gravidade de um CVE, mas tem um problema fundamental: não mede o risco real para sua organização. Um CVE com CVSS 9.8 em um software que você não usa é irrelevante, enquanto um com CVSS 6.5 em seu banco de dados principal pode ser crítico.

A solução é combinar o CVSS com o Exploit Prediction Scoring System (EPSS), desenvolvido pela FIRST. O EPSS prevê a probabilidade de um CVE ser explorado nos próximos 30 dias, usando dados de:

O EPSS é atualizado diariamente e está disponível como feed CSV ou API. A métrica chave é o percentil EPSS: um CVE com EPSS ≥ 0.8 (percentil 80) tem 80% de probabilidade de ser explorado em 30 dias.

Em nossa arquitetura, priorizamos os CVE assim:

CVSS Percentil EPSS Prioridade Ação
≥ 9.0 ≥ 70 Crítica Corrigir em <24h
7.0 - 8.9 ≥ 50 Alta Corrigir em <7 dias
4.0 - 6.9 ≥ 30 Média Avaliar mitigação
< 4.0 < 30 Baixa Monitorar

Exemplo real: Em janeiro de 2024, o CVE-2024-21626 (runc) tinha CVSS 8.6, mas EPSS 0.92 (percentil 92). Embora o CVSS fosse "alto", o EPSS indicava que era quase certo que seria explorado. De fato, em 5 dias apareceram exploits públicos. Equipes que usavam apenas o CVSS o priorizaram como "médio", enquanto as que combinavam CVSS+EPSS o corrigiram antes da publicação dos exploits.

O código para integrar o EPSS em seu pipeline (usando o feed CSV da 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: como evitar 95% do ruído

O maior erro no monitoramento de CVE é não filtrar pelo stack tecnológico real da organização. Uma equipe que usa apenas Python, PostgreSQL e Nginx não deveria receber alertas de vulnerabilidades em Apache Tomcat ou Microsoft Exchange.

A solução é manter um inventário atualizado de:

  1. Software instalado (SO, bibliotecas, frameworks).
  2. Versões exatas (ex.: não "Python 3.x", mas "Python 3.9.7").
  3. Dependências transitivas (ex.: uma biblioteca Python pode depender do OpenSSL).

Ferramentas para gerar esse inventário:

Exemplo de comando com Nuclei para detectar versões de software em um servidor:

nuclei -u https://seuservidor.com -t nuclei-templates/http/technologies/ -json -o technologies.json

O arquivo technologies.json gerará um output como:

[
  {
    "template-id": "nginx-version",
    "info": {
      "name": "Nginx Version Detection",
      "severity": "info",
      "description": "Detecta versão do Nginx",
      "reference": [],
      "tags": ["tech", "nginx"]
    },
    "host": "https://seuservidor.com",
    "matched-at": "https://seuservidor.com",
    "extracted-results": ["nginx/1.21.6"]
  }
]

Com esse inventário, você pode filtrar os CVE do NVD usando os CPE. Exemplo em Python:

import re

Inventário de software (exemplo)

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 # Extrair vendor, product, version do 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 se o produto está no inventário 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 se a versão do CVE é menor ou igual à instalada # (assumindo que o CVE afeta versões <= 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)

Exemplo 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 chave: Essa abordagem requer manter o inventário atualizado. Se um desenvolvedor instalar uma nova biblioteca sem notificar, o sistema não a detectará. A solução é automatizar o inventário com ferramentas como OpenVAS ou Nuclei, e executá-las semanalmente.

Pipeline de alertas: como não sobrecarregar a equipe

O maior risco em um sistema de monitoramento de CVE não é perder uma vulnerabilidade crítica, mas sobrecarregar a equipe com alertas irrelevantes. Um pipeline mal projetado gera:

Nossa arquitetura de pipeline tem 4 etapas:

  1. Ingestão: Download dos feeds (NVD, vendors, EPSS).
  2. Filtro: Eliminação de CVE que não se aplicam ao stack (usando o inventário).
  3. Priorização: Atribuição de prioridade baseada em CVSS+EPSS.
  4. Notificação: Envio de alertas apenas para prioridades críticas e altas, com contexto relevante.

Ferramentas para implementar o pipeline:

Exemplo de configuração do Alertmanager para agrupar alertas por produto:

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 }}%
      *Descrição*: {{ .CommonAnnotations.description }}
      *Ação*: {{ .CommonAnnotations.action }}

Regra de ouro: Nunca envie um alerta sem contexto. Cada notificação deve incluir:

Caso real: como lidamos com o Log4Shell em um cliente da América Latina

Em 9 de dezembro de 2021, foi publicado o CVE-2021-44228 (Log4Shell), com CVSS 10.0. Nosso pipeline o detectou às 10:17 (UTC-3), 37 minutos após aparecer no feed do NVD. Eis o que aconteceu:

  1. Ingestão: O feed JSON do NVD o capturou automaticamente.
  2. Filtro: Nosso inventário mostrou que o cliente usava o Log4j 2.14.1 em 3 servidores.
  3. Priorização: CVSS 10.0 + EPSS 96% (percentil 96) = prioridade crítica.
  4. Notificação: Foi enviada uma alerta para o Slack com:
    • CVE ID e link para o NVD.
    • CVSS 10.0, EPSS 96%.
    • Produtos afetados: "Log4j 2.14.1 nos servidores A, B, C".
    • Descrição: "RCE via JNDI lookup no Log4j 2.x <= 2.14.1".
    • Ação: "Mitigar com -Dlog4j2.formatMsgNoLookups=true ou atualizar para 2.15.0".
  5. Resposta: A equipe de DevOps do cliente aplicou a mitigação em 2 horas e corrigiu para 2.15.0 em 24 horas.

Lições aprendidas:

Esse caso é a razão pela qual a CyberShield inclui monitoramento de CVE em tempo real como parte de seu stack base. Para PMEs da América Latina, onde as equipes de segurança são pequenas, a automação não é um luxo: é a diferença entre conter um ataque ou sofrer uma violação.

Tradeoffs e limitações: o que ninguém te conta

Nenhum sistema de monitoramento de CVE é perfeito. Estes são os tradeoffs que enfrentamos na prática:

  1. Falsos negativos em software não mapeado no NVD:

    O NVD não cobre todos os produtos, especialmente os de fornecedores regionais ou software legado. Exemplo: em 2023, um cliente da América Latina usou um ERP local com uma vulnerabilidade crítica que nunca apareceu no NVD. A solução foi complementar com:

    • Varreduras manuais com OpenVAS/Nuclei.
    • Monitoramento de fóruns de fornecedores locais.
    • Alertas de CERTs regionais (ex.: CERT.br, CSIRT da OEA).
  2. O EPSS não é infalível:

    O EPSS prevê a probabilidade de exploração, mas não é 100% preciso. Em 2022, o CVE-2022-22965 (Spring4Shell) teve EPSS 0.12 (percentil 12) ao ser publicado, mas foi explorado massivamente em 48 horas. A lição: o EPSS é mais uma ferramenta, não um oráculo. Sempre verifique manualmente os CVE com CVSS alto, mesmo que o EPSS seja baixo.

  3. O problema das dependências transitivas:

    Um CVE em uma biblioteca que você não usa diretamente pode afetá-lo se for uma dependência de outro software. Exemplo: um CVE no OpenSSL pode afetar o Nginx, embora o Nginx não esteja listado no CVE. A solução é:

    • Usar ferramentas como dependency-check (OWASP) para analisar dependências.
    • Manter um grafo de dependências atualizado.
  4. A atualização do inventário é manual (até certo ponto):

    Embora ferramentas como OpenVAS e Nuclei automatizem a detecção de software, nem sempre capturam tudo. Exemplo: um desenvolvedor pode instalar uma biblioteca Python com pip install --user, que não aparece nas varreduras globais. A solução é:

    • Varreduras frequentes (semanalmente).
    • Políticas de mudança: notificar a equipe de segurança antes de instalar novo software.
    • Monitoramento de repositórios de código (ex.: GitHub Dependabot).

Esses tradeoffs não são razões para não implementar um sistema de monitoramento de CVE, mas razões para projetá-lo com pragmatismo. Um sistema imperfeito, mas funcional, é melhor do que não ter sistema.

A arquitetura que descrevemos aqui é a que usamos na CyberShield para clientes da América Latina, com ajustes conforme o stack e os recursos de cada organização. Não é a única forma de fazê-lo, mas é uma forma comprovada que equilibra automação, precisão e escalabilidade para equipes pequenas.

O monitoramento de CVE em tempo real não é um projeto que se termina: é um processo contínuo de ajuste. Os feeds mudam, os stacks evoluem e as ameaças se adaptam. A vantagem de um sistema como este é que ele oferece visibilidade em tempo real, permitindo responder antes que uma vulnerabilidade se torne uma violação. Para equipes pequenas, essa visibilidade é a diferença entre ser proativo ou reativo.

Em um ecossistema onde 60% das violações exploram vulnerabilidades conhecidas (segundo o Data Breach Investigations Report 2023 da Verizon), não monitorar os CVE é como navegar sem radar. A pergunta não é se você pode se dar ao luxo de implementar um sistema assim, mas se pode se dar ao luxo de não fazê-lo. A equipe da CyberShield continua refinando essa arquitetura, porque em cibersegurança, a única constante é a mudança — e a única defesa eficaz é a adaptação contínua.

Fontes

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