Análise do ataque à cadeia de suprimentos do Rust e o problema do build.rs

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

  • Um malicioso build.rs o script é executado durante cargo build com os privilégios do processo que invocou o Cargo.
  • O Stable Cargo não oferece nenhuma maneira oficial de compilar uma árvore de dependências, ao mesmo tempo em que se recusa a executar seus scripts de compilação.
  • Seis dos 34 pacotes maliciosos do TrapDoor foram detectados no crates.io, contra 21 no npm e 7 no PyPI.
  • O npm e o pnpm agora bloqueiam, por padrão, scripts de instalação de dependências não aprovados, e o Cargo estável não possui um recurso equivalente para todas as dependências.

Os desenvolvedores do Rust passaram anos ouvindo que a linguagem é segura. Segurança de memória, ausência de disputas de dados em código seguro, um sistema de tipos que detecta em tempo de compilação o que outras linguagens só conseguem identificar em tempo de execução. Nada disso se aplica ao código que é executado antes mesmo de seu programa existir. Em maio de 2026, uma campanha voltada para a cadeia de suprimentos de software chamada TrapDoor publicou 34 pacotes maliciosos em mais de 384 versões no npm, PyPI e crates.io. Nenhum deles esperava que você chamasse o pacote. Eles eram acionados na instalação, na importação ou durante a compilação. Seis dos 34 estavam no crates.io, disfarçados como ferramentas do Sui e do Move, utilizando build.rs para localizar os arquivos de chaves das carteiras de criptomoedas. O autor de um crate pode desativar seu próprio script de compilação no manifesto. Como usuário, você não dispõe de uma opção genérica que desative os scripts de compilação das dependências em toda a árvore. É essa lacuna que este artigo aborda.

O que a TrapDoor fez em três registros

O npm, o PyPI e o crates.io não foram afetados da mesma forma. Dos 34 pacotes identificados, 21 estavam no npm, utilizando scripts pós-instalação para executar uma carga útil compartilhada destinada à coleta de credenciais no momento em que alguém os instalasse. Sete estavam no PyPI, sendo executados durante a importação para buscar uma carga útil remota em JavaScript e executá-la localmente. Apenas seis chegaram ao crates.io, utilizando scripts de compilação em Rust que são executados durante a compilação. É esse padrão que une toda a campanha. Em cada ecossistema, o invasor aproveitou o ponto de entrada de execução que aquele ecossistema já lhe oferecia.

Registro Pacotes nomeados Ganchinho de execução O que aconteceu
npm 21 Scripts do ciclo de vida pós-instalação Ran trap-core.js, um programa de coleta de credenciais compartilhadas com movimentação lateral baseada em SSH
PyPI 7 Execução no momento da importação Recuperei e executei uma carga útil JS remota por meio de node -e
crates.io 6 build.rs scripts de compilação Pesquisei pelos arquivos de chaves das carteiras Sui e Aptos, os criptografei com XOR e os enviei para o GitHub Gists

Os seis pacotes do crates.io – move-analyzer-build, move-compiler-tools, move-project-builder, sui-framework-helpers, sui-move-build-helper, e sui-sdk-build-utils – eram direcionadas especificamente aos desenvolvedores do Sui e do Move, e não à comunidade geral do Rust. O lado do npm sofreu a maior parte dos danos em termos de número de pacotes e sofisticação da carga maliciosa. O lado do crates.io ainda é o mais importante para os engenheiros do Rust, pois mostra um build.rs script que faz exatamente o que um build.rs É para isso que o script foi projetado. Ele é executado discretamente, com os privilégios do processo de compilação, antes mesmo que o próprio aplicativo tenha a chance de ser executado.

Por que o build.rs é uma opção melhor do que um script pós-instalação

Ganchos de execução no npm, no PyPI e no crates.io no ataque à cadeia de suprimentos do TrapDoor Rust
Tanto o npm quanto o pnpm agora bloqueiam, por padrão, scripts de instalação de dependências não aprovados, com uma lista de permissões que você aprova e confirma para os pacotes que realmente precisam deles. O pnpm já faz isso desde a v10, em janeiro de 2025. O npm só chegou a esse ponto com a v12, em julho de 2026, semanas após o TrapDoor; portanto, essas cargas pós-instalação ainda eram executadas por padrão para qualquer pessoa que fizesse a instalação durante a campanha. O Cargo estável não possui uma lista de permissões equivalente para todas as dependências nem um bloqueio padrão. build.rs é um programa em Rust que o Cargo compila e executa antes de compilar o crate ao qual ele pertence, com os privilégios do processo que está executando o Cargo. Ele existe por motivos válidos, como geração de código e ligação nativa, e muitos crates legítimos incluem um. Qualquer dependência cujo script de compilação seja executado pode executar código arbitrário com as permissões disponíveis para o processo do Cargo. O TrapDoor é o que acontece quando alguém usa isso deliberadamente. Os seis crates cujos nomes se assemelham às ferramentas de compilação Sui e Move utilizadas build.rs para procurar em um computador os arquivos de chaves da carteira no momento em que alguém executasse cargo build. O script criptografava com XOR tudo o que encontrava e enviava para o GitHub Gists. Sem nenhum gancho de instalação separado, sem importação, bastava compilar um projeto que, por acaso, dependesse de um dos seis nomes de pacotes. As macros procedurais são a outra via de execução em tempo de compilação no Rust, e o TrapDoor não precisava delas. Uma macro proc é executada dentro do compilador durante a expansão da macro, o que significa que ela só é acionada quando algo realmente a invoca. Um script de compilação é acionado simplesmente porque o crate está presente no gráfico de compilação, e é exatamente isso que o torna a opção mais confiável para um invasor.

Mecanismo Ocorre durante Controle geral do gerenciador de pacotes
script de ciclo de vida do npm Instalar Sim, bloqueado por padrão desde o npm 12
Execução no momento da importação em Python Importação de pacotes Não
Ferrugem build.rs Compilação Não
Macro procedural em Rust Expansão macroeconômica Não

O Cargo não oferece um switch estável e de uso geral que permita ao usuário compilar uma árvore de dependências, recusando, ao mesmo tempo, scripts de compilação de dependências ou a expansão de macros. Há uma única exceção específica. Quando um crate declara um links key, você pode substituir o script de compilação dele na configuração do Cargo, fornecendo você mesmo os metadados; assim, esse script nunca será compilado nem executado. Isso se aplica a shims de bibliotecas nativas, e não a uma dependência arbitrária que decidiu incluir um script de compilação. cargo build --offline impede que o Cargo faça solicitações de rede e um committed Cargo.lock fixam versões, mas nenhuma delas impede que um script de compilação já presente na sua árvore seja executado, nem ajuda se a versão fixada no seu arquivo de bloqueio for a maliciosa.

Onde um script de compilação é executado e o que ele pode acessar

Credenciais que um arquivo `build.rs` malicioso pode acessar em um executador de CI em comparação com o laptop de um desenvolvedor
Um corredor de CI fazendo cargo build geralmente contém credenciais de funções na nuvem, tokens de registro, acesso ao registro de contêineres e, às vezes, chaves de assinatura. Um laptop de desenvolvedor pode conter a maior parte disso, além de chaves SSH, dados de sessão do navegador e código-fonte de tudo o que ainda não foi lançado. É isso que faz com que valha a pena comprometer um host de compilação, em primeiro lugar. Sakshi Grover, gerente sênior de pesquisa da IDC Asia Pacific Cybersecurity Services, disse ao CSO Online depois que o TrapDoor revelou que “uma única estação de trabalho comprometida pode, discretamente, se tornar um ponto de entrada nos pipelines de CI/CD”. Um script de compilação que coleta credenciais é uma forma de acesso, e extrair arquivos de chaves de carteiras diretamente do sistema de arquivos durante uma compilação sem supervisão foi o que a parte do TrapDoor relacionada ao crates.io fez.

A seção dedicada aos assistentes de programação de IA

Como o TrapDoor contaminou os arquivos CLAUDE.md e .cursorrules lidos pelos assistentes de programação de IA
A manipulação maliciosa dos arquivos do assistente de IA pela TrapDoor não foi uma build.rs truque. Isso veio da inserção de código malicioso no payload do npm .cursorrules e CLAUDE.md arquivos como forma de persistência, contendo as instruções maliciosas ocultos por caracteres Unicode de largura zero, além do mesmo agressor abrindo pull requests no GitHub contra projetos de IA e ferramentas de desenvolvimento não relacionados. Ambos os nomes de arquivo são convenções que as ferramentas de codificação de IA utilizam para compreender uma base de código; portanto, um nome de arquivo adulterado constitui uma injeção indireta de prompt. O texto do invasor é inserido em um arquivo que o assistente trata como orientação, em vez de dados. A pré-condição, porém, é mais restrita do que “todas as ferramentas de IA estão comprometidas”. O sucesso da técnica depende de quais arquivos de instruções um determinado assistente descobre, considera confiáveis e segue. Vale a pena fazer isso de qualquer maneira. Procure por arquivos de instruções do assistente em qualquer lugar que não seja a raiz do seu repositório e trate como suspeito, por padrão, qualquer resultado encontrado dentro de um pacote fornecido por terceiros ou de uma dependência de caminho. Isso funciona como uma verificação de CI, desde que você inverta o código de saída para que a detecção de algo realmente falhe a compilação, em vez de aprová-la.

if find . -name 'CLAUDE.md' -o -name '.cursorrules' \
  | grep -vE '^\./(CLAUDE\.md|\.cursorrules)$' | grep -q .; then
  echo "Unexpected AI assistant instruction file found"
  exit 1
fi

Esse é um objetivo diferente de enganar um revisor humano. Corromper um arquivo no momento da persistência significa que o resultado só se manifesta mais tarde, quando um assistente ler o projeto e tratar o arquivo como uma instrução legítima. A solução está, principalmente, no escopo. Restringir os arquivos de instruções nos quais um assistente confia reduz a superfície de ataque, especialmente quando caminhos controlados por dependências são excluídos.

O que realmente se remove ao puxar uma caixa

O registro crates.io faz algo incomum, e em grande parte positivo. As versões publicadas são imutáveis e não podem ser excluídas, apenas revertidas. Isso bloqueia toda uma classe de ataques que afeta os registros mutáveis. Isso também significa que uma reversão é uma medida corretiva menos eficaz do que a maioria das pessoas imagina.

Ação Efeito
Baixar uma versão As novas resoluções ignoram isso, enquanto os arquivos de bloqueio existentes continuam a usá-lo
Retirar todas as versões O nome do crate continua reservado, o código continua disponível para download
Excluir uma versão Não é possível no crates.io

Uma versão retirada que já havia sido gravada em um commit Cargo.lock permanece em uso. Isso é proposital, para que as compilações não falhem por conta própria, mas significa que uma organização que fixou uma versão maliciosa continuará compilando com ela até que alguém realmente altere o arquivo de bloqueio. Execute cargo update --dry-run para ver o que mudaria e, em seguida, executar a correspondência cargo update para reescrever o arquivo de bloqueio assim que você confirmar que as versões de substituição são seguras.

Por que isso sempre iria acontecer com o Rust

Os invasores seguem a adoção. O papel cada vez mais importante do Rust em infraestrutura, criptografia e software de sistemas nos últimos anos fez com que isso fosse uma questão de “quando”, e não de “se”. Crates que eram pequenos projetos paralelos há alguns anos agora estão profundamente integrados às pilhas de produção. Scripts de compilação são culturalmente comuns no Rust, de uma forma que os scripts de pós-instalação não são no npm. Um pacote com um script de pós-instalação chama a atenção dos revisores. build.rs não é o caso, pois os crates que geram código, verificam os recursos da plataforma ou vinculam bibliotecas nativas têm, todos, um motivo legítimo para incluir um. Esse uso legítimo é o que faz com que a mera presença de build.rs um sinal tão fraco. Nada disso significa que este seja o primeiro contato do TrapDoor crates.io com malware. Já em 2023, o registro retirou nove crates que eram vítimas de typosquatting, cujos build.rs os arquivos enviaram os metadados do host para um canal do Telegram, e ataques à cadeia de suprimentos no crates.io têm surgido com tanta frequência que a equipe parou de publicar posts sobre cada um deles em fevereiro de 2026. A novidade em relação ao TrapDoor é que o crates.io surgiu no âmbito de uma campanha coordenada que atingiu o npm e o PyPI na mesma onda. Essas duas plataformas já haviam passado por sua própria versão disso anos antes, em uma escala muito maior, quando o número de pacotes delas atingiu typosquatting e nomes semelhantes que valham a pena para um invasor. O TrapDoor inclui o crates.io no mesmo modelo de ameaças entre ecossistemas que as equipes de segurança já aplicam ao npm e ao PyPI.

Protegendo a cadeia de suprimentos do Rust

SecureChain para Rust verifica um crate antes que ele entre na sua árvore de dependências, analisando o código-fonte em busca de padrões de ataque durante a compilação, incluindo códigos maliciosos build.rs scripts e macros procedurais, e bloqueando aqueles que apresentam falhas. Os crates são recompilados a partir do código-fonte verificado, em vez de serem repassados diretamente do registro público. Esse é o tipo de filtro que precisa estar na frente de um pacote como sui-framework-helpers, porque, uma vez que um inimigo build.rs está na árvore, em execução cargo build já é tarde demais. Ele também continua corrigindo vulnerabilidades em crates que já estão na sua pilha, incluindo aquelas cujos mantenedores não dão mais notícias. O TrapDoor é o problema imediato. A maior parte do que acaba entrando em uma árvore de produção do Rust é a versão mais lenta, e vale a pena abordar isso também. Inscreva-se no Boletim informativo da TuxCare para uma análise como essa na próxima vez que uma campanha escolher um novo nome de pacote e um novo ecossistema para se esconder.

Perguntas frequentes

O que é um ataque à cadeia de suprimentos do Rust?

Um ataque que compromete o código ou as dependências antes que elas cheguem até você, na maioria das vezes por meio de crates maliciosos ou sequestrados no crates.io. No Rust, os scripts de compilação e as macros procedurais são as duas rotas de execução em tempo de compilação mais importantes, pois ambas executam código antes que o aplicativo resultante seja executado.

O que é o build.rs e por que ele é perigoso?

build.rs é um programa em Rust que o Cargo compila e executa antes de compilar o crate ao qual ele pertence, com os privilégios do processo que está executando o Cargo. Ele existe para fins legítimos de geração de código e vinculação nativa; qualquer dependência que o inclua permite a execução de código arbitrário com as mesmas permissões que o processo de compilação do Cargo possui.

O TrapDoor realmente precisava do build.rs, ou qualquer hook de compilação do Rust teria funcionado?

build.rs foi o suficiente, e exigiu o mínimo de esforço, então foi isso que as seis crates utilizaram. Uma macro procedural é a outra opção em tempo de compilação, mas ela só é executada quando o código que a utiliza realmente invoca a macro, enquanto um script de compilação é executado simplesmente porque a crate está no gráfico de compilação. Os invasores escolheram build.rs porque isso lhes proporcionou o ponto de execução de que precisavam.

Retirar uma caixa faz com que ela seja removida do crates.io?

Não. A remoção impede que novas resoluções selecionem essa versão, mas mantém a possibilidade de baixá-la, e uma versão já fixada em um Cargo.lock continua sendo utilizada. Não é possível excluir uma versão publicada no crates.io.

Quais eram os arquivos corrompidos do assistente de IA no TrapDoor?

O .cursorrules e CLAUDE.md Os arquivos utilizavam caracteres Unicode de largura zero para ocultar instruções destinadas a assistentes de programação de IA. A campanha também tentou introduzir arquivos semelhantes por meio de pull requests no GitHub em projetos não relacionados.

Resumo
Análise do ataque à cadeia de suprimentos do Rust e o problema do build.rs
Nome do artigo
Análise do ataque à cadeia de suprimentos do Rust e o problema do build.rs
Descrição
O TrapDoor ocultou scripts maliciosos no arquivo `build.rs` em seis crates que roubavam chaves de carteiras durante a compilação, e o Cargo ainda não consegue bloqueá-los.
Autor
Nome da editora
TuxCare
Logotipo da editora

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.