A auditoria de carga e as falhas na segurança das dependências do Rust

Os patches do php2shell (CVE-2026-109618 e CVE-2026-109619) para o PHP em fim de vida (EOL) já estão disponíveis. Como as respostas do atendimento de vendas estão mais demoradas do que o normal devido à alta demanda, a maneira mais rápida de obter os pacotes corrigidos é adquirir o ELS para Runtimes on-line (abre em uma nova aba). Leia as perguntas frequentes sobre os patches

Vá direto para um resumo gerado por IA desta postagem do blog

  • Resuma esta postagem com o Perplexity
  • Resuma esta postagem com o Gemini

Principais conclusões

  • O sistema de auditoria de carga só tem acesso aos avisos que já foram registrados por alguém.
  • Os scripts de compilação e as macros proc executam código arbitrário em tempo de compilação, e o Cargo na versão estável não permite desativar isso.
  • Uma caixa abandonada não tem data de validade, portanto nada expira e você só recebe um aviso se alguém a denunciar.
  • Quando um aviso é divulgado sem uma versão corrigida, a correção passa a ser de sua responsabilidade.

Quando uma equipe do Rust decide levar a sério a segurança das dependências, o primeiro passo é quase sempre o mesmo. Instalar o cargo audit, integrá-lo à integração contínua (CI), ver se ele é aprovado e ficar mais tranquilo.

É uma boa estratégia. Mas a auditoria de carga responde a uma questão mais específica do que a maioria das equipes imagina. Ela diz: Cargo.lock e informa quais pacotes têm alertas registrados contra eles. Isso não é o mesmo que saber se o código que você está prestes a compilar é seguro para compilação.

As ferramentas do Rust são sólidas nos aspectos que a comunidade da linguagem priorizou. Compilações reproduzíveis, versões imutáveis, arquivos de bloqueio com checksum. As lacunas não são resultado de descuido. Elas são o que acontece quando uma cadeia de ferramentas é construída com base em dependências honestas, em vez de hostis.

O que a auditoria de carga realmente verifica

Três coisas, embora se atribua à ferramenta um número maior de méritos.

Ele verifica os pacotes no seu arquivo de bloqueio (lockfile) em relação ao Banco de Dados de Alertas da RustSec. Ele sinaliza versões retiradas. E exibe alertas informativos — e é nesse ponto que o Rust faz algo que a maioria dos gerenciadores de pacotes ignora completamente.

cargo install cargo-audit --locked
cargo audit

A RustSec divide suas descobertas em categorias, e os três tipos que não se enquadram como vulnerabilidades têm um peso prático maior do que a maioria das equipes imagina.

Tipo de recomendação O que isso significa É reprovado na auditoria de carga por padrão
Vulnerabilidade Uma falha de segurança com um ID RUSTSEC atribuído Sim
Sem manutenção O mantenedor declarou, ou deixou claro, que deixou de dar suporte ao projeto Não, apenas um aviso
Unsound Uma API segura que pode provocar um comportamento indefinido Não, apenas um aviso
Aviso Outras informações que merecem destaque Não, apenas um aviso

Nenhuma das categorias de informação falha por si só; portanto, uma tarefa de CI que execute uma simples auditoria do Cargo é aprovada, mesmo com crates sem manutenção presentes na árvore. Geralmente, é exatamente isso que as equipes acreditam estar detectando.

cargo audit --deny warnings

Isso muda a situação. Você também pode excluir categorias mais específicas, como “sem manutenção”, “com falhas” ou “retirado”, caso queira destacar um tipo específico de resultado sem incluir os demais. É de se esperar que a primeira execução em um projeto maduro gere bastante ruído.

A tag “unmaintained” só existe se alguém a atribuir. Um crate cujo mantenedor deixou de enviar commits discretamente em 2023 e nunca anunciou nada não gera nenhum aviso. Uma execução limpa do cargo audit não indica se suas dependências ainda têm alguém por perto.

O que cada ferramenta de segurança do Rust abrange

Essas ferramentas se diferenciam em dois aspectos que são mais importantes do que o número de recursos: se é necessário que um ser humano tenha realmente revisado o código e se elas podem interromper uma compilação.

Ferramenta Verificação preliminar Pode causar falha na compilação Precisa de revisão humana
auditoria de carga Lockfile em relação aos alertas da RustSec Sim, por meio do seu código de saída Não
recusa de carga Avisos, licenças, caixotes proibidos, fontes Sim, orientado por políticas Não
veterinário especializado em carga Se os seus critérios de auditoria foram atendidos Sim, quando faltam auditorias e nada isenta a caixa Sim
fenda de carga Rede distribuída de revisões de código baseada na confiança Não Sim
cargo geiger Volume de código inseguro na árvore Não Não
carga passível de auditoria Incorpora a lista de dependências ao binário Não Não

O `cargo deny` é aquele que é subutilizado em relação ao que ele realmente faz. Ele abrange as mesmas recomendações de segurança do RustSec que o `cargo audit`, acrescenta políticas de licença e restrição e permite que você inclua fontes na lista de permissões, de modo que um crate de um registro que você nunca aprovou não possa ser instalado sem que você perceba. As versões atuais reprovam na verificação de alertas de vulnerabilidade e avisos; por padrão, reprovam em casos de alertas não mantidos em qualquer parte da árvore e reprovam em alertas inválidos em suas dependências diretas — esse é o comportamento que a maioria das equipes desejava desde o início.

O `cargo auditable` resolve um problema diferente. Depois que um binário em Rust é compilado, não é confiável recuperar sua lista exata de dependências. O comando `cargo audit bin ` consegue reconstruí-la parcialmente ao analisar mensagens de pânico, e sua própria documentação é agradavelmente direta quanto aos limites. O código C incorporado fica invisível para ele, e cerca de metade das dependências do Rust desaparecem porque o compilador é muito bom em remover panics que nunca podem ocorrer. Incorporar a lista real no momento da compilação resolve isso, e custa apenas uma palavra no seu comando de compilação.

Correr cargo tree --duplicates em paralelo a qualquer auditoria que você esteja realizando. A presença de várias versões do mesmo crate em uma única árvore torna a correção mais complicada do que parece, pois a atualização de um caminho de dependência ainda pode deixar uma versão mais antiga compilada no seu binário.

A primeira lacuna é o momento certo

Todas as ferramentas dessa tabela operam a partir de um gráfico de dependências que o Cargo já resolveu. Elas podem causar falha na compilação ou bloquear um lançamento. O que nenhuma delas faz é, desde o início, manter um crate fora do gráfico resolvido.

Para a maioria dos problemas de dependência, isso é suficiente. Uma crate cuja vulnerabilidade já é conhecida continua sendo vulnerável dez minutos depois, e detectá-la na integração contínua (CI) já é cedo o suficiente.

No caso de código malicioso, ele está no lado errado da linha do tempo, pois o Rust executa código não confiável durante a compilação. Os scripts de compilação são executados como parte de cargo build. As macros procedimentais são executadas dentro do compilador. Nenhuma delas recebe uma sandbox do Cargo; portanto, ambas são executadas com as permissões de quem iniciou a compilação, tendo acesso ao sistema de arquivos, à rede e a quaisquer credenciais que o ambiente de compilação venha a possuir.

O Stable Cargo não possui nenhum sinalizador para desativar nenhum dos dois.

cargo vendor vendored/
find vendored/ -name build.rs | wc -l

Tente fazer isso em um projeto de verdade. Um serviço de médio porte, com algumas centenas de crates na árvore, pode facilmente gerar dezenas de scripts de compilação, e cada um deles, pertencente a um crate que realmente é compilado para o seu destino, é executado em uma compilação limpa. É bem provável que ninguém da equipe tenha lido nem mesmo um deles.

Isso não é hipotético. Em maio de 2026, pesquisadores que estavam documentando o Campanha TrapDoor encontrou caixotes como, por exemplo, sui-framework-helpers e move-compiler-tools destinado aos desenvolvedores do Sui e do Move. O build.rs Os scripts procuravam por arquivos de chaves de carteiras locais assim que um projeto era compilado e enviavam o que encontravam para o GitHub Gists. Sem hook de instalação, sem importação, apenas cargo build fazendo exatamente o que foi projetado para fazer.

O Rust não tem nada parecido com npm install --ignore-scripts. É possível ler o código-fonte de um crate antes de compilá-lo, e isso deve ser feito para qualquer conteúdo confidencial. O que o Cargo estável não faz é executar uma compilação normal ignorando os scripts de compilação das dependências e as macros proc; portanto, o processo de “auditar e depois compilar” continua sendo uma tarefa manual, e não uma opção de linha de comando.

A verificação de um crate antes que ele chegue ao desenvolvedor e sua compilação a partir de código-fonte verificado em um ambiente controlado estão entre os poucos controles que ocorrem antes da execução em tempo de compilação. Esse problema de tempo é o ponto central em torno do qual o SecureChain para Rust foi desenvolvido, em vez de adicionar mais uma passagem sobre uma árvore que já foi baixada.

A segunda lacuna é que ninguém corrige nada

O RustSec registra vulnerabilidades. Ele não as corrige.

Essa distinção permanece teórica até o momento em que o aviso que você tem diante de si não tiver uma versão corrigida. Aí, o problema se torna grave, e as opções de solução se reduzem rapidamente.

O volume também continua crescendo. O RustSec mantém 170 alertas com datas de divulgação em 2025, e os alertas datados de 2026 já ultrapassaram esse total em maio, chegando a 257 em meados de agosto. Este é o quarto ano consecutivo em que o número aumenta, com cerca de 160 dos registros deste ano classificados como vulnerabilidades e o restante dividido entre descobertas sem manutenção e não válidas. Esses números também aumentam gradualmente após o fato, já que alertas referentes a divulgações mais antigas continuam chegando meses depois. Isso é positivo para o projeto. Mas também representa uma carga operacional crescente para quem utiliza os dados, pois mais descobertas em uma árvore de código que ninguém corrige na origem significam apenas mais problemas que não podem ser resolvidos simplesmente atualizando a versão.

O Rust também mantém seus usuários atuais satisfeitos. Os desenvolvedores mais uma vez o classificaram como a linguagem mais admirada na pesquisa com desenvolvedores de 2025 do Stack Overflow, com 72%, embora o índice de admiração avalie quantos usuários atuais desejam continuar usando a linguagem, e não a rapidez com que sua adoção está crescendo. De qualquer forma, muitas empresas já utilizam o Rust em produção sem nenhuma prática estabelecida sobre o que fazer em relação a um crate que tenha um aviso de segurança e nenhuma correção disponível.

Quando não existe uma versão corrigida, todas as opções são incômodas. Você pode criar um fork do crate, aplicar a correção e mantê-lo em seu próprio nome. Você pode substituir a dependência, o que geralmente significa reescrever tudo o que a utilizava. Você pode corrigi-la localmente por meio de [patch.crates-io] e ficar com esse patch indefinidamente. Você pode documentar um controle compensatório e aceitar o risco. Ou pode contratar alguém cuja função específica seja aplicar correções retroativamente ao código upstream que foram deixadas de lado.

A adaptação de uma correção de segurança para uma versão cujo mantenedor já não está mais envolvido é uma disciplina diferente da criação de novos recursos. Isso exige testes de regressão, validação de compatibilidade e um compromisso deliberado de não alterar o comportamento, o que é basicamente o oposto do que o desenvolvimento upstream se propõe a fazer.

A terceira lacuna são as caixas que nunca são oficialmente retiradas de circulação

O PHP divulga datas de fim de vida útil (EOL). O Node também, seguindo seu próprio cronograma. Um crate que uma pessoa publicou em 2019 não divulga nada, pois, para começar, nunca houve um compromisso de suporte que fosse encerrado.

O registro em crates.io isso torna a situação mais complicada de uma maneira específica. As versões publicadas são, na prática, imutáveis. A exclusão só é possível em um intervalo muito restrito, para crates com quase nenhum download e sem dependências; portanto, a remoção manual é a verdadeira solução. Essa imutabilidade é um verdadeiro ponto forte de segurança em comparação com registros que permitem tags mutáveis. Isso também significa que um crate abandonado continua instalável, é resolvido normalmente e não deixa nada no Cargo.lock o que sugere que seu mantenedor tenha abandonado o projeto há três anos.

Nenhuma ferramenta agrega os sinais que indicariam isso, então essa parte continua sendo manual. Compare a data da última versão com o número de issues em aberto. Verifique se o repositório do GitHub está arquivado, algo que o Cargo nunca menciona. Conte os proprietários listados na página do crates.io, pois um único proprietário representa um “fator de risco” igual a um. E observe se o crate é uma dependência de compilação ou uma macro proc, já que essas são executadas em tempo de compilação, independentemente do nível de manutenção que recebam.

Correr cargo owner --list <crate> em relação a qualquer elemento relevante para a segurança em sua árvore de código. Um único proprietário em um crate que seja compilado no seu binário de produção representa um risco à cadeia de suprimentos que a simples comparação com alertas não é capaz de identificar.

Para saber quais resultados realmente importam, é preciso esse tipo de contexto. O status de manutenção, se existe uma correção, se o crate está no seu caminho de compilação ou apenas nas dependências de desenvolvimento. A correspondência de alertas não fornece nenhuma dessas informações, então as equipes acabam priorizando com base no ID do RUSTSEC, em vez de na exposição real.

Em que aspectos o Cargo Vet ajuda e em que aspectos não ajuda

O Cargo Vet adota uma abordagem diferente e merece ser mais amplamente adotado do que tem sido até agora. Em vez de comparar alertas, ele aplica critérios de auditoria em todo o seu gráfico de dependências, utilizando auditorias realizadas pela sua própria equipe, além das que você importa de organizações que publicam as suas.

cargo vet init
cargo vet suggest

É bom saber antes de começar: cargo vet init isenta propositalmente tudo o que já está na sua árvore, para que a adoção não sobrecarregue o CI logo no primeiro dia. O backlog vem à tona por meio de cargo vet suggest, e você troca isenções por auditorias reais no ritmo que sua equipe conseguir manter. Importar auditorias de organizações maiores cobre uma parte considerável do acúmulo de tarefas sem que ninguém da sua equipe precise revisar esse código pessoalmente.

Os limites são estruturais. A cobertura depende de alguém ter auditado uma versão da qual você realmente depende, e uma nova versão precisa de evidências novas, a menos que uma auditoria importada ou uma isenção já a abranja. As auditorias delta mantêm isso sob controle, já que você geralmente revisa as diferenças em relação a uma versão já aprovada, em vez de começar do zero. Uma auditoria humana também envolve uma avaliação subjetiva sobre a qualidade e a intenção do código, não uma garantia. Os revisores deixam passar coisas, especialmente em scripts de compilação ofuscados.

A confiança delegada ainda é melhor do que nenhuma confiança. Ela apenas apresenta uma curva de cobertura, e essa curva é mais estreita exatamente onde se encontram crates novos ou pouco conhecidos — que, por acaso, é justamente onde os pacotes maliciosos preferem aparecer.

O que realmente executar na integração contínua

Escolha com base no estágio em que seu projeto se encontra, em vez de instalar tudo de uma vez.

Como ainda não há nada definido hoje, comece com cargo deny check advisories sources. Ele abrange as recomendações do RustSec, adiciona a lista de permissões de código-fonte em uma única etapa e, por padrão, trata as principais categorias de recomendações como erros que impedem a compilação.

Se a auditoria de carga já estiver em andamento, adicione --deny warnings para que os resultados desatualizados e incorretos deixem de passar despercebidos; em seguida, classifique a lista resultante de acordo com a presença ou não da crate no seu caminho de compilação.

Se você enviar binários para clientes ou para ambientes regulamentados, adicione a opção “cargo auditable” para que o artefato enviado inclua sua própria lista de dependências. Reconstruir essa lista posteriormente é uma tarefa desagradável e resulta em um resultado incompleto.

Se seus agentes de compilação possuírem credenciais de nuvem ou chaves de assinatura, considere a execução em tempo de compilação como o principal risco e reduza o prazo de validade dessas credenciais, pois, uma vez iniciada a compilação, os scripts de compilação de dependências podem ser executados antes mesmo que seu próprio código seja executado.

E se a execução em tempo de compilação for inaceitável no seu modelo de ameaças, o Cargo por si só não consegue impor esse limite. O controle precisa ser antecipado à resolução, passando pela triagem e recompilação dos crates antes que eles cheguem à compilação, ou por um ambiente de compilação isolado que presuma que o código seja malicioso.

Seus resultados variam de acordo com a estrutura da árvore. Um projeto com 40 dependências diretas e sem frameworks que utilizem muitas proc-macros é uma auditoria viável. Um serviço que utilize runtimes assíncronos, serialização e um framework web pode facilmente atingir várias centenas de crates transitivos com muitos pontos de execução em tempo de compilação, e qualquer recomendação que trate esses dois casos da mesma forma vem de alguém que não executou o `cargo tree` no segundo caso.

Onde o SecureChain para Rust se encaixa

Tudo o que foi mencionado acima diz respeito a identificar falhas, não a corrigi-las. O `cargo audit` indica o que já foi sinalizado. O `cargo vet` indica o que já foi revisado por alguém. Nenhuma das duas ferramentas faz nada em relação a um crate que execute código malicioso antes que qualquer uma delas o analise, e nenhuma delas gera uma correção para um aviso que não tenha um patch do upstream.

É para isso que o SecureChain para Rust foi criado. Ele recompila crates a partir do código-fonte em ambientes isolados, verifica se há malware e padrões suspeitos durante a instalação e mantém a aplicação de patches de acordo com o SLA à medida que novos CVEs são divulgados. Quando a manutenção do desenvolvedor original é encerrada, o Suporte de Ciclo de Vida Ilimitado assume o mesmo crate e continua fornecendo correções enquanto ele permanecer em sua pilha, de modo que uma dependência abandonada nunca se torne, sem que você perceba, uma dependência sem patch em sua árvore de código.

Se você está tentando se antecipar ao que está oculto em suas dependências transitivas, o webinar da TuxCare sobre o “iceberg das dependências” aborda em profundidade como as vulnerabilidades (CVEs) se propagam pelas cadeias de dependências que permanecem invisíveis, mesmo quando seu painel de controle parece estar em ordem.

Perguntas frequentes

O que é a auditoria de carga?

Ele compara as caixas na sua Cargo.lock em comparação com o Banco de Dados de Alertas da RustSec e relata vulnerabilidades, versões retiradas e alertas informativos sobre crates sem manutenção ou com falhas. Ele não analisa o código-fonte dos crates e não intercepta instalações, embora seu status de saída o torne um excelente filtro de CI. Um recurso experimental cargo audit fix O subcomando pode atualizar alguns requisitos de dependências vulneráveis, mas é preciso instalar o cargo audit com o recurso de correção ativado para que isso ocorra.

A auditoria de carga é reprovada no caso de caixotes sem manutenção?

Não por padrão. Os avisos informativos, inclusive aqueles que não recebem manutenção, são exibidos como alertas, a menos que você configure de outra forma. Execute cargo audit --deny warnings falhar nesses aspectos ou ignorar uma única categoria, como “sem manutenção”, e esperar que a primeira execução demore muito tempo em um projeto já consolidado.

Qual é a diferença entre auditoria de carga e verificação de carga?

A auditoria de carga verifica se há algum aviso registrado contra uma caixa, o que não exige nenhuma ação de sua parte. A verificação de carga verifica se seu gráfico de dependências atende aos critérios de auditoria que você configurar, utilizando suas próprias auditorias, auditorias importadas, auditorias delta e quaisquer isenções que você tenha definido. Uma nova versão requer novas evidências, a menos que já haja algo que a abranja, e uma auditoria delta geralmente significa revisar apenas as diferenças em relação a uma versão já auditada.

O Cargo pode impedir a execução de scripts de compilação?

Não. O Stable Cargo não possui nenhum sinalizador compatível para desativar scripts de compilação ou macros procedurais, os quais executam código arbitrário durante a compilação com acesso a tudo o que estiver disponível no ambiente de compilação.

Como faço para encontrar caixotes abandonados na minha árvore de dependências?

Não existe um comando específico para isso. Execute cargo audit --deny warnings para identificar avisos arquivados e sem manutenção, verifique as datas das últimas versões, se o repositório está arquivado e o número de proprietários por meio de cargo owner --list para qualquer assunto relacionado à segurança.

O que acontece quando um aviso da RustSec não tem uma versão corrigida?

Nada resolve isso automaticamente. Você faz um fork e corrige o crate, substitui a dependência, aplica um patch local por meio de [patch.crates-io] e mantê-lo, documentar um controle compensatório ou contratar um fornecedor que aplique correções retroativas a crates cujos mantenedores originais tenham deixado de mantê-los.

Junte-se a mais de 4.500 profissionais de Linux e código aberto!

2 vezes por mês. Sem spam.

Índice
Obtenha as respostas sobre segurança de código aberto de que você precisa

Junte-se a mais de 4.500 profissionais de Linux e código aberto!

2 vezes por mês. Sem spam.