Fala Guerreiros e Guerreiras!

Hoje ao som da obra prima do Sólstafir - Svartir Sandar, navegando em águas gélidas da Islândia ao post-metal.

Uma aplicação pode ter uma boa arquitetura, testes automatizados, cobertura de código elevada e um pipeline de CI/CD funcionando perfeitamente. Ainda assim, pode carregar uma vulnerabilidade conhecida em uma biblioteca, no próprio framework ou em uma dependência indireta.

É nesse cenário que entram as CVEs.

Neste artigo, vamos entender o que significa uma CVE, como interpretar a gravidade de uma vulnerabilidade e como incorporar verificações de segurança a um projeto Ruby on Rails sem transformar a atualização de dependências em uma operação de risco.

1. O que é uma CVE?

CVE é a sigla para Common Vulnerabilities and Exposures. O programa CVE atribui identificadores padronizados a vulnerabilidades de segurança conhecidas publicamente, facilitando a comunicação entre desenvolvedores, pesquisadores, empresas e ferramentas de segurança.

Um identificador tem, normalmente, este formato:

CVE-2025-12345

Esse exemplo é apenas ilustrativo, não representa uma vulnerabilidade específica.

Uma CVE pode estar relacionada a diferentes tipos de problemas, como:

  • execução de código não autorizada;
  • exposição de informações sensíveis;
  • falhas de autenticação ou autorização;
  • ataques de negação de serviço;
  • injeção de comandos ou consultas;
  • leitura ou manipulação indevida de arquivos.

É importante entender uma diferença: a CVE é o identificador da vulnerabilidade, não uma medida completa do risco que ela representa para determinada aplicação.

Para pesquisar informações, podemos consultar o programa CVE e a National Vulnerability Database (NVD).

2. CVE e CVSS são a mesma coisa?

Não. Embora estejam relacionados, os conceitos são diferentes.

A CVE identifica uma vulnerabilidade. Já o CVSS (Common Vulnerability Scoring System) fornece uma pontuação e uma classificação de severidade, considerando características técnicas da falha.

De maneira geral, as classificações mais conhecidas são:

Pontuação CVSS Classificação
0,0 Nenhuma
0,1 a 3,9 Baixa
4,0 a 6,9 Média
7,0 a 8,9 Alta
9,0 a 10,0 Crítica

Essas faixas correspondem ao CVSS v3.x; outras versões podem apresentar diferenças de classificação.

Mas atenção: uma vulnerabilidade classificada como crítica não significa automaticamente que qualquer aplicação que utilize aquela biblioteca esteja explorável. Da mesma forma, uma falha de severidade média pode representar um risco importante dependendo dos dados tratados, da exposição da aplicação e das permissões envolvidas.

A análise precisa considerar pelo menos quatro aspectos:

  1. Severidade: qual é o impacto técnico potencial?
  2. Exposição: o componente vulnerável está acessível a usuários ou sistemas externos?
  3. Aplicabilidade: a aplicação utiliza a funcionalidade afetada?
  4. Mitigação: existe uma correção disponível ou uma medida temporária eficaz?

A pontuação ajuda a priorizar. Ela não substitui a análise de risco.

Referência: NVD — informações sobre CVEs e CVSS.

3. Por que isso importa em projetos Ruby on Rails?

Uma aplicação Rails não é composta apenas pelo código escrito pela equipe.

Ela utiliza o Ruby, o framework Rails, gems diretamente declaradas no Gemfile e diversas dependências indiretas. Também depende do sistema operacional, de imagens de contêiner, do servidor web, do banco de dados e de outros componentes da infraestrutura.

Considere um projeto com esta estrutura simplificada:

  • Ruby;
  • Rails;
  • Devise para autenticação;
  • Sidekiq para processamento em segundo plano;
  • Redis para filas e armazenamento;
  • PostgreSQL para persistência;
  • gems adicionais para arquivos, relatórios e integrações.

Uma vulnerabilidade pode estar em qualquer componente afetado, e nem sempre a dependência problemática foi adicionada diretamente pela equipe.

Por exemplo, uma gem pode depender de outra biblioteca que apresenta uma falha conhecida. Mesmo que o projeto não tenha declarado essa segunda biblioteca diretamente, ela pode aparecer no Gemfile.lock.

É por isso que revisar somente o código da aplicação não é suficiente.

4. Primeiro passo: auditar as gems com Bundler Audit

Uma das ferramentas mais úteis nesse contexto é o bundler-audit, mantido pelo projeto RubySec.

Ele verifica o arquivo Gemfile.lock em busca de dependências com vulnerabilidades registradas na base de avisos de segurança utilizada pela ferramenta. Também verifica fontes inseguras de gems.

Repositório oficial: rubysec/bundler-audit.

Instalação

Podemos adicionar a ferramenta ao grupo de desenvolvimento do projeto:

group :development do
  gem "bundler-audit"
end

Depois, instalamos a dependência:

bundle install

Também é possível instalar a ferramenta separadamente, conforme a política de ferramentas adotada pela equipe.

Executando a auditoria

Para atualizar a base de avisos e verificar as dependências:

bundle exec bundle-audit check --update

O comando utiliza o executável bundle-audit e verifica as versões registradas no Gemfile.lock.

Quando uma vulnerabilidade é encontrada, a saída pode apresentar informações como:

  • nome da gem;
  • versão instalada;
  • identificador da vulnerabilidade;
  • descrição do problema;
  • severidade, quando disponível;
  • versão ou versões recomendadas para correção;
  • referência para consultar o aviso completo.

Um resultado encontrado não deve ser ignorado automaticamente. É necessário consultar o aviso, confirmar quais versões são afetadas e entender o impacto no projeto.

Para gerar um relatório em JSON:

bundle exec bundle-audit check \
  --update \
  --format json \
  --output bundle-audit.json

A disponibilidade e o comportamento de opções podem variar conforme a versão instalada. Consulte a documentação da versão utilizada no projeto.

Um detalhe importante

Executar uma auditoria apenas uma vez não resolve o problema permanentemente.

Novos avisos são publicados, dependências recebem atualizações e a situação do projeto pode mudar. Por isso, essa verificação deve fazer parte da rotina de manutenção e do pipeline de integração contínua.

5. Encontrou uma vulnerabilidade. E agora?

Imagine que a auditoria identificou uma versão vulnerável de uma gem.

A primeira reação não deve ser atualizar todas as dependências indiscriminadamente.

Uma atualização ampla pode alterar APIs, introduzir incompatibilidades e provocar falhas em funcionalidades que estavam funcionando corretamente.

Um procedimento mais cuidadoso seria:

Etapa 1 — Identificar a origem da dependência

Consulte a árvore de dependências:

bundle info nome-da-gem

Para entender quais dependências introduzem determinada gem, utilize:

bundle why nome-da-gem

Esse segundo comando depende da versão do Bundler instalada. Caso não esteja disponível, consulte a documentação correspondente ou examine a árvore de dependências por outro meio.

Etapa 2 — Consultar o aviso de segurança

Leia a referência indicada pela ferramenta e confirme:

  • quais versões são afetadas;
  • qual é a versão corrigida;
  • quais condições tornam a falha relevante;
  • se existem limitações ou mitigações documentadas.

Não confie somente no título de um alerta ou em uma pontuação.

Etapa 3 — Atualizar a dependência necessária

Quando a correção estiver disponível, uma opção é atualizar a gem de forma conservadora:

bundle update --conservative nome-da-gem

O comportamento exato depende das restrições definidas no Gemfile e das relações entre dependências. Em alguns casos, será necessário atualizar outras gems ou ajustar as restrições de versão.

Revise o Gemfile.lock para entender quais componentes foram alterados.

Etapa 4 — Executar os testes

Após a atualização:

bundle exec rspec

Se o projeto tiver verificações adicionais:

bundle exec rubocop
bundle exec brakeman

Esses comandos verificam aspectos diferentes: testes automatizados, padrões de código e possíveis problemas de segurança identificáveis por análise estática.

Testes passando não provam que a vulnerabilidade foi corrigida. É preciso confirmar a versão instalada e executar novamente a auditoria de dependências.

A documentação oficial do Rails também recomenda atualizações cuidadosas de dependências: Securing Rails Applications.

6. CVE não é a única verificação de segurança

Uma auditoria de dependências é importante, mas tem um escopo específico. Ela não substitui a análise do código da aplicação.

Em um projeto Rails, podemos combinar ferramentas com objetivos complementares:

Ferramenta Objetivo principal
Bundler Audit Identificar gems afetadas por avisos conhecidos
Brakeman Detectar possíveis problemas de segurança no código Rails
RSpec Verificar comportamentos esperados por meio de testes
RuboCop Verificar estilo, convenções e regras de análise estática
Ferramentas de auditoria de contêineres Identificar componentes vulneráveis em imagens e pacotes do sistema

Cada ferramenta tem limitações. Nenhuma delas, isoladamente, garante que a aplicação esteja segura.

Também é importante considerar a versão do Ruby, o sistema operacional, a imagem de contêiner e os serviços externos. Uma auditoria de gems não examina automaticamente toda a infraestrutura.

7. Automatizando a verificação no CI/CD

Uma prática recomendada é executar a auditoria de dependências automaticamente em cada pipeline relevante.

Um exemplo de etapa para um ambiente de CI que já tenha Ruby e Bundler configurados seria:

bundle install
bundle exec bundle-audit check --update
bundle exec rspec

O objetivo é identificar problemas antes que uma alteração seja integrada ou implantada.

Em um ambiente real, convém separar as etapas, armazenar os relatórios como artefatos e definir uma política para falhas de segurança.

Por exemplo:

  • bloquear a integração quando uma vulnerabilidade crítica ou de alto risco for confirmada, conforme a política do projeto;
  • abrir uma tarefa de correção para alertas que precisem de investigação;
  • registrar exceções com justificativa, responsável e prazo de revisão;
  • manter uma rotina de atualização da base de avisos;
  • repetir a auditoria antes da implantação, quando apropriado.

Uma exceção não deve virar uma autorização permanente para ignorar alertas.

Se a equipe decidir aceitar temporariamente um risco, essa decisão precisa ser documentada, justificada e revisada. Quando a ferramenta permite ignorar um aviso específico, prefira uma exceção restrita e rastreável em vez de desativar toda a verificação.

8. O problema de ignorar alertas sem investigar

Imagine uma aplicação de gestão comercial que utiliza Rails para processar pedidos, registrar pagamentos e controlar estoque.

A auditoria encontra uma dependência vulnerável. A equipe, pressionada pelo prazo, adiciona uma exceção para que o pipeline continue passando.

O sistema segue funcionando, os testes continuam verdes e a implantação ocorre normalmente.

Mas o alerta não desapareceu por ter sido ignorado. A vulnerabilidade continua exigindo análise e, dependendo das condições de exploração, pode representar um risco para a aplicação e seus dados.

O mesmo problema acontece quando uma equipe atualiza uma biblioteca sem consultar a documentação e sem validar a compatibilidade.

Segurança exige equilíbrio: corrigir vulnerabilidades com prioridade, evitar mudanças desnecessárias e comprovar que a correção funcionou.

9. Um checklist para projetos Rails

Antes de considerar a auditoria concluída, verifique:

  • [ ] O Gemfile.lock está versionado e corresponde às dependências utilizadas?
  • [ ] A base de avisos foi atualizada durante a auditoria?
  • [ ] Os alertas encontrados foram analisados e priorizados?
  • [ ] As dependências vulneráveis foram atualizadas para versões corrigidas compatíveis?
  • [ ] O arquivo Gemfile.lock foi revisado?
  • [ ] Os testes automatizados passaram após as alterações?
  • [ ] A auditoria foi executada novamente?
  • [ ] As exceções foram justificadas e possuem prazo de revisão?
  • [ ] A versão do Ruby, o sistema operacional e as imagens de contêiner também são verificados?
  • [ ] O processo será repetido automaticamente no CI/CD?

Conclusão: segurança é um processo contínuo

CVE não é apenas uma sigla que aparece em relatórios de segurança. É uma referência para investigar vulnerabilidades conhecidas e tomar decisões técnicas fundamentadas.

No Ruby on Rails, ferramentas como Bundler Audit facilitam a identificação de gems vulneráveis. Entretanto, identificar uma falha é somente o começo: precisamos compreender o impacto, atualizar com cuidado, executar testes e confirmar que a correção foi aplicada.

Uma boa arquitetura, testes automatizados, análise estática e dependências atualizadas se complementam. Nenhum desses elementos substitui os demais.

E fica uma reflexão: se o pipeline está verde, mas ninguém verifica as vulnerabilidades das dependências, estamos medindo a qualidade do software ou apenas confirmando que ele continua funcionando?

Em desenvolvimento de software, funcionar é necessário. Manter o sistema seguro também faz parte da responsabilidade técnica.


Referências