2億4,500万ダウンロード、86分間 ― arrayref サプライチェーン攻撃
- Home
- ブログ
Joeです。2026年8月20日、ほとんど誰も意識していないが、ほとんど全員がコンパイルしているRustクレートに、毒入りのリリースが公開されました。手口に新しさはありません。だからこそ記録する価値があるのです。盗まれた公開権限、信頼されている名前に似せた名前、そしてビルドスクリプト。何が起きたのか、数字が何を意味するのか、そしてこの種のインシデントが「CIログの脚注」で済むか「認証情報流出事案」になるかを分ける対策をまとめます。
-
実際に何が起きたのか
2026年8月20日、crates.io に arrayref 0.3.10 の侵害されたリリースが現れ、さらに internment 0.8.7 と append-only-vec 0.1.9 も同様に公開されました。いずれも proc-macro1 というタイポスクワットクレートへの依存を追加していました。ほぼすべてのRustプロジェクトが既に取り込んでいるクレート名と、1文字しか違わない名前です。そのクレートのビルドスクリプトが、コンパイル中にリモートのバイナリをダウンロードして実行します。影響を受けた2つのクレートのメンテナーは、共犯ではなくアカウントを乗っ取られたと見られています。Rust Security Response Team は該当リリースを削除し、アカウントをロックし、攻撃者が作成した6つのクレート(proc-macro1、proc-macro-en、aovine、arone、aronenao、tinymember)を削除しました。
-
ビルド時実行は、実行時より悪い
ここを過小評価しているチームが多いです。ビルド時マルウェアは、プログラムを実行しなくても動きます。cargo build だけで十分です。つまり、開発者のノートPCで、そして何より重要なことにCIランナーの中でコードが実行されます。レジストリトークン、クラウド認証情報、署名鍵、デプロイ先へのSSHアクセスを抱えている、まさにそのマシンです。実行時のバックドアは利用者を必要としますが、ビルド時のバックドアはパイプラインだけで足ります。そしてパイプラインこそ、多くの組織で高権限の認証情報と第三者の任意コードが、設計上隣り合わせになっている場所です。
-
数字と、その誤読み方
arrayref の累計ダウンロード数は約 2億4,500万、直近90日で約 5,370万、直接依存として列挙しているクレートは 403 件です(推移的依存を含めればはるかに多くなります)。ただしこれらは「名前の影響範囲」を示す数字であって、被害者数ではありません。実際に暴露したかどうかを決めるのはもっと狭い条件です。当該時間帯に、依存グラフを新規解決したビルドが自社環境にあったか、そしてそれが悪意のあるバージョンを拾ったか。ロックファイルをコミットしていれば、答えはほぼ確実に「いいえ」です。
-
86分は「あっという間」ではない
悪意のある arrayref リリースは 07:15 UTC に公開され、08:41 にはインデックスから削除されました。暴露時間は 86分、他のリリースも同じく86~107分です。非常に迅速な対応であり、それでもなお短くはありません。CIにとって90分は、ごく普通の午前中です。依存更新ボット、ナイトリービルド、マージキュー、クリーンなコンテナで一から再解決するリリースパイプライン。自動化はアドバイザリを待ってくれません。「窓は小さかった」というとき、人は人間の時間で測っていますが、攻撃者はビルドの時間で測っています。
-
依頼先環境でのトリアージ手順
最初の問いは「影響を受けたか」ではなく、「そもそもその問いに答えられるか」です。まずコミット済みロックファイルと、直近のビルドが実際に解決した内容を差分し、次にCIログを対象バージョンの完全一致で検索します。その後、ビルドステップ中の外部通信を探します。コンパイルがバイナリを取得する正当な理由はないからです。そしてそのランナーが到達できた範囲を確認します。環境変数にどのトークンがあり、どこまでの権限を持ち、事象後にローテーションされたか。これらのどれかの答えが「そのログは保存していない」なら、その欠落自体が指摘事項です。そして次のインシデントでも同じ指摘になります。
-
被害を囲い込めた対策
ロックファイルをコミットし、CIでは --locked を付けてビルドしましょう。新しい悪意のバージョンが黙って引き込まれることを防げます。ビルドは、本当に必要な工程以外は外部通信を遮断したサンドボックスで実行してください。この対策だけで、大半のビルドスクリプト型ドロッパーは無力化します。ビルドスクリプトは信頼できないコードとして扱うこと。実際そのとおりだからです。各パイプラインには機能する最小限の権限だけを与え、長期有効のレジストリ鍵より短命のトークンを優先します。顧客に出荷するものについては依存を vendor またはミラーします。どれも目新しいものではなく、地味なものばかりですが、「アラート」で済むか「インシデント」になるかを分けます。
-
メンテナーもあなたの攻撃面である
ここでの技術的な欠陥は、Rust にも cargo にもクレート自体にもありませんでした。一人の公開権限です。依存しているすべてのレジストリは、結局のところ「あなたのビルドにコードを押し込める個人アカウントの一覧」です。レジストリ側は、公開時の二要素認証必須化、スコープを限定した短命の公開トークン、影響範囲の大きいパッケージの新規リリースに対する遅延または検証工程で、このリスクを小さくできます。利用者側は、「latest」を価値と見なさないことです。なお、今回のキャンペーンと既知の国家関与が疑われる活動とのインフラ重複を指摘する研究者もいます。文脈としては有用ですが、帰属分析が何かを修正してくれたことは一度もありません。
-
今週実施すべきチェックリスト
すべてのロックファイルとCIログを、arrayref 0.3.10、internment 0.8.7、append-only-vec 0.1.9、および proc-macro1 への参照で検索してください。見つかった場合は、そのランナーが参照できた認証情報をすべてローテーションし、反証できるまでビルドホストは侵害済みとして扱ってください。その上で、対症療法だけでなく構造的な変更を行いましょう。依存の固定とコミット、ビルド中の外向き通信の遮断、CI認証情報の短命化。次に汚染されるパッケージは別の名前ですが、この3つの対策は名前を気にしません。
コメント(5件)
-
ci_greg 2日前 返信外向き通信の遮断は、うちの会社でやっと承認が取れた対策です。fetch 工程の後は、ビルドのほぼ何もインターネットを必要としていませんでした。
-
たいていそうなります。例外リストは想像よりもっと短く、それを明文化すること自体に半分の価値があります。
-
-
86分という対応時間は、セキュリティチームとして本当に見事です。スレッドでの叩かれ方は公平ではありません。
-
cargo update を実行するナイトリージョブがありました。ログには何も見つかりませんでしたが、それはたまたま30日間保存していたからです。設計ではなく運でした。
-
その一文を、次のリスクレビューにそのまま書いてください。「運で答えられた」こと自体が指摘事項です。
-
-
ダウンロード数の多いクレートへの公開時二要素認証必須化は、明らかな一手に見えます。なぜレジストリ側の対応が遅いのでしょうか。