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:
- 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.
- Falsos positivos em produtos da América Latina: O NVD usa o campo
productpara 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. - 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:*:*:*:*:*:*:*oucpe: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:
- NVD JSON feed como fonte primária (por sua cobertura global).
- Feeds de vendors específicos (Microsoft, Red Hat, Ubuntu) para reduzir a latência em produtos críticos.
- APIs de repositórios como GitHub Advisory Database para software open-source (ex.: bibliotecas Python/Node.js).
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:
- Atividade em repositórios de exploits (ex.: Exploit-DB, GitHub).
- Menções em fóruns de hackers (ex.: dark web, Telegram).
- Padrões de exploração na natureza (ex.: dados de honeypots).
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:
- Software instalado (SO, bibliotecas, frameworks).
- Versões exatas (ex.: não "Python 3.x", mas "Python 3.9.7").
- Dependências transitivas (ex.: uma biblioteca Python pode depender do OpenSSL).
Ferramentas para gerar esse inventário:
- OpenVAS: Scanner de vulnerabilidades que também gera um inventário de software. Ideal para servidores e endpoints.
- Nuclei: Ferramenta da ProjectDiscovery para varredura de vulnerabilidades, que inclui templates para detectar versões de software. Mais leve que o OpenVAS, mas requer configuração manual.
- Dependabot/GitHub Advisory: Para repositórios de código (detecta vulnerabilidades em dependências).
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:
- Fadiga de alertas (alert fatigue): a equipe ignora as notificações por excesso de ruído.
- Falsos positivos: alertas que não se aplicam ao stack da organização.
- Falsos negativos: vulnerabilidades críticas que se perdem no ruído.
Nossa arquitetura de pipeline tem 4 etapas:
- Ingestão: Download dos feeds (NVD, vendors, EPSS).
- Filtro: Eliminação de CVE que não se aplicam ao stack (usando o inventário).
- Priorização: Atribuição de prioridade baseada em CVSS+EPSS.
- Notificação: Envio de alertas apenas para prioridades críticas e altas, com contexto relevante.
Ferramentas para implementar o pipeline:
- Prometheus + Alertmanager: Para monitoramento e alertas. Configure o Alertmanager para agrupar alertas similares e evitar spam.
- Webhooks do Slack/Teams: Para notificações em tempo real. Use mensagens com formato claro e ações rápidas (ex.: botão para marcar como "corrigido").
- Jira/ServiceNow: Para rastreamento de vulnerabilidades. Crie tickets automáticos para prioridades críticas e altas.
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:
- O CVE ID e seu link para o NVD.
- O CVSS e o percentil EPSS.
- O produto afetado e sua versão em seu stack.
- Uma descrição clara do impacto (ex.: "RCE no Nginx 1.21.6").
- A ação recomendada (ex.: "Atualizar para o Nginx 1.23.1").
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:
- Ingestão: O feed JSON do NVD o capturou automaticamente.
- Filtro: Nosso inventário mostrou que o cliente usava o Log4j 2.14.1 em 3 servidores.
- Priorização: CVSS 10.0 + EPSS 96% (percentil 96) = prioridade crítica.
- 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".
- 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:
- A latência do NVD importa: Se tivéssemos esperado 8 horas, o cliente teria ficado exposto durante o fim de semana (quando muitas equipes não monitoram alertas).
- O EPSS foi chave: Embora o CVSS já fosse 10.0, o EPSS 96% confirmou que era quase certo que seria explorado, o que acelerou a resposta.
- O inventário salvou horas: Sem um inventário atualizado, teríamos que escanear manualmente os servidores para verificar se usavam o Log4j.
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:
- 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).
- 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.
- 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.
- Usar ferramentas como
- 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
- 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 <
