← Blog

Gerenciando vulnerabilidades de código aberto nas suas dependências

Guia prático de gestão de vulnerabilidades open source: encontre dependências vulneráveis, priorize com CVSS, EPSS, KEV e reachability, e remedie CVEs.

Bruno Baldo·28 de set. de 2026·Atualizado em 14 de set. de 2026·13 min de leitura·Revisado por Rainforest Technologies

O código aberto é o substrato do software moderno. As bibliotecas que você instala, e as bibliotecas de que essas bibliotecas dependem, compõem a maior parte do que de fato vai para produção — o que significa que a segurança da sua aplicação é, em grande medida, a segurança de um código que você não escreveu. A gestão de vulnerabilidades open source é a disciplina de encontrar, priorizar e remediar as dependências vulneráveis nesse fornecimento de código de terceiros antes que um atacante o faça. É uma prática central dentro da análise de composição de software, e acertar nela é a diferença entre um scanner que gera ruído e um programa que reduz risco de forma mensurável.

Este artigo é um mergulho a fundo no lado das vulnerabilidades do SCA: de onde vêm as vulnerabilidades em dependências, como distinguir uma que é genuinamente urgente de uma que é apenas severa, e como a remediação de CVEs realmente funciona quando a falha está enterrada três níveis abaixo na sua árvore de dependências.

De onde vêm as vulnerabilidades em dependências

Toda dependência que você adiciona é código executando com os privilégios da sua aplicação, e vem com seu próprio histórico de falhas descobertas. Essas vulnerabilidades chegam por duas portas.

Dependências diretas são os pacotes que você instalou deliberadamente — aqueles listados no seu package.json, pom.xml, requirements.txt ou go.mod. Você as escolheu, você consegue vê-las e, quando uma delas tem uma vulnerabilidade, a correção normalmente está sob seu controle.

Dependências transitivas são as que suas dependências diretas trazem, e as que essas trazem, recursivamente. Um único pacote que você instala pode discretamente trazer dezenas de outros a reboque. É aqui que realmente mora a maior parte do risco: estudos de projetos reais encontram, de forma consistente, que as dependências transitivas superam em muito as diretas, e elas são exatamente o código que a maioria das equipes nunca olha. Uma vulnerabilidade em um pacote de que você nunca ouviu falar, importado por um pacote de que você nunca ouviu falar, ainda está rodando na sua aplicação. Como essa exposição indireta é tão fácil de passar despercebida, ela merece um tratamento próprio — veja dependências transitivas e segurança para o quadro completo.

A consequência prática é que você não consegue gerenciar o que não consegue enumerar. O primeiro trabalho da gestão de vulnerabilidades open source é produzir um inventário completo e resolvido de cada dependência na árvore, direta e transitiva, nas versões exatas que de fato vão rodar.

Os bancos de dados e identificadores de vulnerabilidades

Um inventário de dependências só se torna útil quando você o cruza com vulnerabilidades conhecidas, e essas vivem em bancos de dados públicos com seus próprios identificadores.

  • CVE (Common Vulnerabilities and Exposures) é o esquema de nomeação universal. Um ID de CVE como CVE-2021-44228 é um rótulo estável e globalmente único para uma falha específica, e é o identificador ao qual todo o resto se refere.
  • NVD (National Vulnerability Database) enriquece os CVEs com pontuações de severidade, faixas de versões afetadas e referências. É autoritativo, mas nem sempre rápido; pode haver um atraso entre um CVE ser publicado e o NVD analisá-lo por completo.
  • GHSA (GitHub Advisory Database) publica avisos vinculados a ecossistemas de pacotes específicos (npm, PyPI, Maven e assim por diante). Como os avisos são expressos em termos de nomes de pacotes e faixas de versões reais, eles se mapeiam de forma limpa sobre a sua árvore de dependências, e muitas vezes aparecem antes de o NVD alcançá-los.
  • OSV (Open Source Vulnerabilities) é um schema e um banco de dados agregado projetado especificamente para código aberto. Ele normaliza avisos de muitos ecossistemas em um formato legível por máquina e preciso quanto à versão, o que torna a correspondência automatizada muito mais confiável do que interpretar faixas de versões em texto livre.

Uma boa ferramenta recorre a várias dessas fontes ao mesmo tempo, porque nenhuma fonte isolada é completa ou tempestiva para todos os ecossistemas. O identificador que as amarra é o CVE, mas são os avisos específicos de ecossistema (GHSA, OSV) que costumam permitir que um scanner afirme com precisão que a sua versão instalada está afetada.

Pontuação e priorização: severidade não é urgência

Se você tratar cada CVE divulgado como uma emergência, vai esgotar sua equipe muito antes de ficar sem avisos. A habilidade na gestão de vulnerabilidades open source está na priorização — separar o punhado de vulnerabilidades que de fato ameaçam você das muitas que não ameaçam. Quatro sinais, usados em conjunto, tornam isso possível.

CVSS (Common Vulnerability Scoring System) fornece uma pontuação de severidade de 0 a 10. O número que você costuma ver é a pontuação base, que descreve as características intrínsecas da falha no abstrato. Mas o CVSS também define uma pontuação ambiental que ajusta ao seu contexto — se o componente afetado está exposto, o que ele de fato comprometeria no seu sistema. Um base 9,8 em uma biblioteca que só roda em uma ferramenta de desenvolvimento isolada em sandbox não representa o mesmo risco que um base 7,5 no seu serviço de autenticação exposto à internet. A severidade base é um ponto de partida, não um veredito.

EPSS (Exploit Prediction Scoring System) responde a uma pergunta diferente: qual a probabilidade de esta vulnerabilidade ser explorada em ambiente real no curto prazo? Ele expressa isso como uma probabilidade. Uma falha de CVSS alto com um EPSS muito baixo costuma ser prioridade menor do que uma falha de CVSS moderado que os atacantes estão sondando ativamente.

KEV (o catálogo Known Exploited Vulnerabilities da CISA) é o sinal mais forte de todos: lista vulnerabilidades que estão confirmadamente sendo exploradas no mundo real. Se um CVE na sua árvore está na lista KEV, ele vai para a frente da fila independentemente das demais pontuações. Isso deixa de ser risco teórico.

Reachability corta o restante do ruído. Uma vulnerabilidade só importa se o trecho de código vulnerável for de fato invocado pela sua aplicação. A análise de reachability rastreia se o seu código — ou o código das suas dependências — em algum momento chama a função afetada. Se a função vulnerável nunca é alcançada, o CVE pode ser um caso genuíno de falsa urgência: presente no inventário, mas não explorável no seu uso. A reachability é uma das formas mais eficazes de encolher uma fila de triagem de centenas de descobertas para as poucas dezenas que estão realmente ativas.

Juntando tudo, a pergunta de priorização não é "quão severo é isto?", mas "é severo, provável de ser explorado, sabidamente explorado e alcançável na nossa aplicação?" Essa visão composta transforma a saída bruta de um scanner em uma lista de trabalho ranqueada e acionável.

Remediando dependências diretas vs. transitivas

Uma vez que você sabe o que corrigir, o caminho de remediação depende muito de o pacote vulnerável ser uma dependência direta ou transitiva.

Para dependências diretas, as opções são relativamente limpas:

  • Atualizar para uma versão corrigida. Este é o padrão e normalmente a resposta certa — a maioria dos CVEs é corrigida em um release posterior.
  • Aplicar patch na vulnerabilidade específica, quando um mantenedor ou sua ferramenta fornece uma correção pontual sem um salto completo de versão.
  • Substituir o pacote por uma alternativa mantida, se o projeto está abandonado e nunca será corrigido.
  • Aceitar o risco com uma justificativa documentada quando a vulnerabilidade genuinamente não é alcançável ou não é aplicável, registrando o porquê para que a decisão seja auditável e não ressurja como ruído a cada scan.

Para dependências transitivas, você tem um problema mais difícil: não dá para simplesmente atualizar um pacote que você nunca importou. As abordagens são:

  • Atualizar o pacote pai que traz a dependência transitiva vulnerável, de modo que ela resolva naturalmente para uma versão corrigida. Esta é a correção mais limpa quando existe um pai mais novo.
  • Forçar uma versão segura usando o mecanismo de override do seu gerenciador de pacotes — overrides no npm, resolutions no Yarn, dependencyManagement no Maven, arquivos de constraints no pip. Eles dizem ao resolver para usar uma versão corrigida do pacote transitivo mesmo que nada o tenha declarado diretamente. Use-os com cuidado: você está sobrescrevendo o que um mantenedor esperava.
  • Substituir ou aceitar, como nas dependências diretas, quando não existe caminho de atualização.

Nos dois casos, a correção tem de ser verificada: subir uma versão pode resolver um CVE e introduzir outro, então a remediação é seguida por um novo scan, não presumida como concluída.

O problema da atualização

Se atualizar sempre funcionasse sem atritos, gerenciamento de dependências seria um problema resolvido. Não é, e esse atrito é o motivo pelo qual dependências vulneráveis se acumulam.

A tensão central é manter-se atual versus manter-se estável. Uma atualização de versão maior para corrigir um CVE pode trazer mudanças de API que quebram compatibilidade e forçam uma refatoração que você não tinha previsto no orçamento. Equipes que ficam para trás — presas a uma versão maior antiga porque atualizar é doloroso — muitas vezes descobrem que a versão corrigida está a vários releases incompatíveis de distância, transformando uma correção de segurança em um projeto de migração.

Lockfiles (package-lock.json, yarn.lock, poetry.lock, go.sum) são essenciais aqui. Eles fixam a versão resolvida exata de cada dependência, direta e transitiva, para que os builds sejam reprodutíveis e o resultado de um scan corresponda de fato ao que é entregue. Mas um lockfile também congela versões vulneráveis no lugar até que você o atualize deliberadamente, e é por isso que regenerar e revisar lockfiles faz parte da manutenção de rotina, e não de um passo único.

A resposta duradoura é tornar as atualizações pequenas e frequentes, em vez de grandes e raras. Manter-se razoavelmente atual significa que cada atualização de segurança é um salto menor em vez de um pulo de várias versões, e mantém você perto o suficiente dos releases mantidos para que uma correção costume estar a uma atualização de distância.

Respondendo à divulgação de um zero-day

De tempos em tempos surge uma vulnerabilidade que transforma o gerenciamento de dependências de higiene rotineira em uma correria com todo mundo mobilizado — uma biblioteca amplamente usada, uma falha crítica explorável remotamente, exploração ativa em questão de horas. A divulgação do Log4Shell na biblioteca Log4j é o exemplo de referência: incontáveis aplicações foram afetadas por meio de uso profundamente transitivo, e a pergunta mais difícil para a maioria das organizações foi simplesmente será que estamos afetados, e onde?

É aqui que o trabalho de base compensa. Um software bill of materials (SBOM) atualizado transforma aquela auditoria manual, apavorada e de dias, em uma consulta: busque nos seus SBOMs o pacote e a faixa de versões afetados e você tem suas aplicações expostas em minutos. Uma ferramenta de SCA que cruza continuamente o seu inventário com novos avisos consegue sinalizar o CVE recém-divulgado em todo o seu parque no momento em que ele é publicado.

Vale ser honesto quanto aos limites. Um SBOM e o SCA aceleram drasticamente a análise de impacto; eles não deixam você imune. Você ainda tem de atualizar, sobrescrever ou mitigar, e, se nenhum patch existe ainda, pode precisar de uma solução temporária. O que uma boa ferramenta lhe compra é velocidade e certeza sobre o escopo — o que, nas primeiras horas de um zero-day, é muitas vezes a diferença entre uma resposta controlada e o caos.

Monitoramento contínuo

A mudança de mentalidade mais importante de todas é esta: uma dependência que é segura hoje pode ser vulnerável amanhã. Você não mudou nada — o mundo mudou. Um novo CVE é divulgado contra uma versão que você entregou meses atrás e, de repente, uma aplicação limpa tem uma descoberta crítica.

Essa realidade torna insuficiente o scanning em um ponto único no tempo. A gestão de vulnerabilidades open source tem de ser contínua: seus artefatos em produção e seus SBOMs são reavaliados contra os bancos de dados à medida que novos avisos chegam, e alguém é notificado quando uma dependência antes limpa se torna vulnerável. Monitorar o software que você já roda é tão importante quanto escanear o código que você está prestes a entregar.

Gating no CI/CD, SLAs e controle de ruído

Para operacionalizar tudo isso, a maioria dos programas maduros converge para algumas práticas.

Coloque um portão no pipeline. Integre o SCA ao CI para que um pull request que introduza uma dependência vulnerável seja sinalizado na mudança que o causou, quando a correção é mais barata. Faça o build falhar em novas descobertas acima de um limiar acordado, em vez de sobre todo o backlog, para que o portão bloqueie o risco novo sem manter cada build refém da dívida histórica.

Defina SLAs por severidade. Defina, e acorde com a engenharia, quão rápido cada camada precisa ser remediada — por exemplo, descobertas críticas e listadas no KEV em dias, altas em semanas e severidades menores em uma cadência de rotina. Amarrar o relógio à severidade priorizada (não ao CVSS bruto) mantém os compromissos realistas e focados no risco real.

Controle o ruído, deliberadamente. A forma mais rápida de matar um programa de SCA é inundar os desenvolvedores com descobertas sobre as quais eles não podem agir. Use a reachability para suprimir CVEs inalcançáveis, faça a deduplicação da mesma vulnerabilidade que aparece em vários serviços e registre decisões de risco aceito para que não reapareçam a cada scan. O objetivo é uma lista curta e confiável — cada item nela real, ranqueado e com dono.

Nenhum desses riscos de dependência existe isolado do resto da segurança da sua aplicação. Componentes vulneráveis e desatualizados continuam sendo uma das categorias de risco do OWASP Top 10 (2025), e as falhas na cadeia de suprimentos de software são acompanhadas como a categoria A03 — um reconhecimento direto de que o código que você importa é hoje uma das principais formas pelas quais aplicações são comprometidas. A gestão de vulnerabilidades open source é como você aborda essa categoria na prática. Veja OWASP para saber como ela se encaixa no panorama de risco mais amplo.

Como a Rainforest ajuda

Fazer tudo isso à mão — resolver a árvore de dependências completa, cruzá-la com vários bancos de dados de vulnerabilidades, pontuar descobertas em CVSS, EPSS, KEV e reachability, e acompanhar a remediação ao longo do tempo — é exatamente o trabalho que a ferramenta de SCA existe para automatizar. A Rainforest traz a análise de composição de software para dentro do seu pipeline para que você possa inventariar cada dependência direta e transitiva, expor os CVEs que de fato afetam as versões que você roda, e priorizá-los pela probabilidade de exploração e pela reachability em vez de pela severidade bruta. Como a Rainforest gera e monitora continuamente um SBOM para as suas aplicações, um zero-day recém-divulgado vira uma busca em todo o seu parque em vez de um exercício de emergência, e a orientação de remediação aponta para a atualização ou o override que de fato elimina a descoberta.

Se você quer colocar a gestão de vulnerabilidades open source sob controle em toda a sua árvore de dependências, agende uma demonstração e passaremos por isso com as suas próprias aplicações.

Perguntas frequentes

O que é gestão de vulnerabilidades open source?

Gestão de vulnerabilidades open source é a prática de encontrar, priorizar e remediar vulnerabilidades conhecidas nas dependências de código aberto de terceiros que suas aplicações usam — tanto os pacotes que você instala diretamente quanto os transitivos que esses pacotes trazem. Envolve construir um inventário completo de dependências, cruzá-lo com bancos de dados de vulnerabilidades como NVD, GitHub Advisories e OSV, ranquear as descobertas por risco no mundo real, remediá-las por meio de atualizações ou overrides, e monitorar continuamente o software em produção à medida que novas vulnerabilidades são divulgadas. É uma parte central da análise de composição de software.

Qual é a diferença entre CVSS e EPSS?

O CVSS (Common Vulnerability Scoring System) mede quão severa é uma vulnerabilidade — seu impacto técnico intrínseco, em uma escala de 0 a 10. O EPSS (Exploit Prediction Scoring System) mede quão provável é que uma vulnerabilidade seja explorada em ambiente real no curto prazo, expresso como uma probabilidade. Eles respondem a perguntas diferentes: uma falha pode ser altamente severa (CVSS alto) e, ainda assim, improvável de ser explorada (EPSS baixo), ou moderadamente severa e alvo ativo. Usados em conjunto — idealmente ao lado do catálogo KEV da CISA e da análise de reachability — eles dão uma noção muito melhor da urgência real do que a severidade sozinha.

Como corrijo uma vulnerabilidade em uma dependência transitiva?

Como você nunca importou uma dependência transitiva diretamente, normalmente não dá para simplesmente atualizá-la. A correção mais limpa é atualizar a dependência direta (o pai) que a traz, para que ela resolva para uma versão corrigida. Se não existe uma versão de pai adequada, use o mecanismo de override do seu gerenciador de pacotes — overrides no npm, resolutions no Yarn, dependencyManagement no Maven, ou um arquivo de constraints no pip — para forçar o resolver a usar uma versão segura. Se nenhum dos dois funciona, você pode substituir o pacote problemático ou, quando a falha é genuinamente inalcançável, aceitar o risco com uma justificativa documentada. Sempre refaça o scan depois para confirmar a correção.

O que é análise de reachability?

A análise de reachability determina se o trecho de código vulnerável em uma dependência é de fato invocado pela sua aplicação. Um pacote pode conter um CVE sério que nunca importa para você porque o seu código — e o resto da árvore de dependências — nunca chama a função afetada. Ao rastrear quais funções vulneráveis são genuinamente alcançáveis, essa análise filtra descobertas que estão presentes no seu inventário mas não são exploráveis no seu uso, o que reduz drasticamente a falsa urgência e permite às equipes concentrar o esforço de remediação nas vulnerabilidades que estão realmente ativas.

Com que frequência devo escanear dependências?

Continuamente. O scanning deve acontecer no CI a cada mudança, para que novas dependências vulneráveis sejam pegas no pull request que as introduz, e também deve rodar continuamente contra seus artefatos em produção e seus SBOMs. O motivo é que uma dependência segura hoje pode ser vulnerável amanhã: novos CVEs são divulgados contra versões que você já entregou sem que você mude nada. Um scan único captura um único momento; só o monitoramento contínuo pega vulnerabilidades que surgem em código já rodando em produção.

Bruno Baldo

Escrito por

Bruno Baldo

CMO

Um pouco de marketing e um pouco de curiosidade e temos a receita pra criar um apaixonado por cyber!

Continue lendo