セキュリティ
アプリは低リスクでも、ビルドパイプラインはそうではありません。
ソフトウェアが社内向けで、用途が限られ、地味なものであれば、セキュリティの優先順位を下げるのは合理的です。しかし、サプライチェーン攻撃はアプリが何をするかなど気にしません。狙うのは、すべてのアプリが共有するパイプラインとパッケージです。
更新日
その考え方は、ある程度までは正しい
よく耳にする考え方で、たいていはもっともな理由があります。アプリは社内ダッシュボードやデータパイプライン、あるいは数人のユーザーしかいない小さなサービスです。攻撃者が欲しがるものは何も保持していません。セキュリティ予算は、まず顧客向けの製品に回されます。
その論理はアプリケーションについては成り立ちます。しかし、アプリケーションのビルド方法については成り立ちません。何を出荷していようと、どのチームにも認証情報を含むCIパイプラインと、自分たちが書いたのではない依存関係ツリーがあります。これらは共有されているからこそ攻撃する価値があり、そこが侵害されれば、その認証情報が触れられるあらゆるもの、つまりレジストリ、クラウドアカウント、他のリポジトリにまで被害が及びます。
アプリの用途を問わなかった攻撃
以下のインシデントはいずれも、特定の種類のアプリケーションを狙ったものではありません。いずれも、ソフトウェアのビルドに使われていたツールやパッケージを通じてチームに到達しました。
tj-actions/changed-files(2025年)
変更されたファイルを検出する、広く使われているGitHub Actionが侵害されました。CISAによれば、悪意のあるバージョンは2025年3月12日から3月15日まで公開されており、この侵害によってアクセスキー、GitHubのパーソナルアクセストークン、npmトークン、RSA秘密鍵などのシークレットが漏えいしました。Wizの報告では、このコードはCIランナーのメモリをダンプしたため、パブリックリポジトリではシークレットがワークフローログに出力されました。バージョンタグでこのアクションを参照していたワークフローは、リポジトリの中身にかかわらず悪意のあるコードを実行しました。
Shai-Hulud npmワーム(2025年)
2025年9月、CISAは500以上のnpmパッケージを侵害した自己増殖型ワームについて警告を発しました。このワームは、GitHubのパーソナルアクセストークンと、AWS、Google Cloud、AzureのクラウドAPIキーを収集しました。Palo Alto Networks Unit 42は、このワームが盗んだnpmトークンを使って被害者の他のパッケージの感染バージョンを公開した手口や、後の波ではpre-installの段階で実行され、CI/CDパイプラインへの到達範囲を広げたことを報告しています。
Shai-Hulud and other supply chain attacks
npmワームShai-Huludがインストール時に認証情報を盗み、それを使ってさらに侵害されたパッケージを公開した手口と、それに先立つ攻撃を解説します。
Kubernetes Community Days Helsinki 2026でのPetteri Pulkkinen、Erika Marttinen、SBOMbastic: Getting Ready for Upcoming EU Cybersecurity Regulation in Software Supply Chainsの4:30~7:57。
Codecov Bash Uploader(2021年)
攻撃者はCodecovのDockerイメージのビルドプロセスにあったエラーを突いて認証情報を抜き取り、多くのチームがCIで実行していたBash Uploaderスクリプトを改ざんしました。2021年1月31日から4月1日まで、改ざんされたスクリプトは、CI環境で利用可能な認証情報、トークン、鍵を含む環境変数を第三者に送信できる状態でした。発覚したのは、ある顧客がスクリプトのチェックサムが一致しないことに気付いたためです。
xz utils(2024年)
Linuxディストリビューションに含まれている可能性のあるデータ圧縮ライブラリ、XZ Utilsのバージョン5.6.0と5.6.1に悪意のあるコードが埋め込まれました。CISAは、5.4.6など侵害されていないバージョンへのダウングレードと、悪意のある活動の調査を勧告しました。圧縮ライブラリほど地味な依存関係はそうありませんが、それでも標的になったのです。
event-stream(2018年)
協力的なメンテナーを装った人物が人気のnpmパッケージevent-streamを乗っ取り、バージョン3.3.6に悪意のある依存関係flatmap-streamを追加しました。npmチームの報告によれば、ペイロードが狙っていたのは特定のアプリケーション、Copayのビットコインウォレットだけでした。それでも、event-streamをインストールした他のすべての人にも悪意のあるコードが届きました。
これらのインシデントの共通点
- ビルド時またはインストール時に発生した。悪意のあるコードが実行されたのは、本番のアプリではなく、開発者のマシンとCIランナーでした。
- 認証情報を狙っていた。標的はパイプライン内のトークンと鍵でした。それらは、ビルド中のプロジェクトを越えて扉を開くからです。
- 信頼された名前を通じて入り込んだ。見慣れたアクション、見慣れたパッケージ、見慣れたスクリプトです。マルウェアをインストールしようと決めた人は誰もいません。
- 事後の最初の問いは同じだった。自社のビルドのいずれかが問題のバージョンを取り込んだか、そしてそれは何に到達できたか。各ビルドが何を使ったかの記録がないチームは、それを再構成しなければなりませんでした。
最小限の対策とは
基本をカバーするのに、セキュリティチームは必要ありません。GitHubとCISAの助言の大半は、短いリストに収まります。
- サードパーティのGitHub Actionsはタグではなく完全なコミットSHAに固定し、タグが移動しても実行内容が変わらないようにする。
- ロックファイルをコミットし、依存関係のバージョンを問題のないリリースに固定する。
- CIトークンには機能する範囲で最小限の権限を与え、使用しているものにインシデントが及んだらローテーションする。
- 開発者と公開用のアカウントには、フィッシング耐性のある多要素認証を必須にする。
- 各ビルドが何をインストールしたかの記録を残し、「影響を受けたか?」に記憶ではなくデータで答えられるようにする。
最初の4つは設定の問題です。5つ目はツールが必要になるため、ほとんどの小規模チームが省略しているものです。
少ない労力でCRACIを活用する
CRACIは、アプリやワークフローを変更することなく、記録の保持を担い、ネットワークの境界を加えます。
- ジョブごとに1行。
runs-onをcraciに変更します。GitHub Actionsのワークフローはそのままで、実行結果はこれまでどおりGitHubに表示されます。 - すべてのビルドからSBOM。CRACIは各ジョブが実際に取り込んだパッケージを、キャッシュから復元されたパッケージも含めて記録し、その結果をCycloneDXまたはSPDXでエクスポートします。
- ジョブごとのネットワークトレース。インシデントが発表されたとき、どのビルドが影響を受けたパッケージを取り込み、各ジョブがどこに接続したかを確認できます。
- デフォルト拒否に切り替えられるエグレスポリシー。ジョブに必要なパッケージソースだけを許可すれば、侵害されたステップが見つけたものを送れる先は少なくなります。ポリシーはフェイルクローズで動作し、違反があればアラートが発生します。
- 継続的な再評価。監視対象のSBOMは新たな脆弱性が公開されるたびに再チェックされるため、誰も確認していないというだけで古いビルドが「クリーン」なままになることはありません。
限界も明確にしておきます。エグレスポリシーがあっても、tj-actionsの侵害でシークレットがパブリックなログに出力されるのは防げなかったでしょうし、漏えいしたトークンを元に戻せるツールはありません。固定とローテーションは引き続き重要です。CRACIが変えるのは、自社が影響を受けたかどうかにどれだけ早く答えられるか、そして侵害されたステップがどこまで到達できるかです。
最初のワークフローを動かすには、GitHub Appをインストールし、1行をruns-on: craciに変更するだけです。
費用
CRACIが課金するのはビルド時間のみです。1vCPU分あたり$0.002(デフォルトの2vCPUランナーでは$0.004)を秒単位で計測し、月額料金もSBOMごとの課金もありません。詳しい条件は料金をご覧ください。対象となるスタートアップはスタートアッププログラムに申し込むことで、最低10万分の無料ビルド時間と手厚いオンボーディングを受けられます。
EUでソフトウェアを販売している場合は、Cyber Resilience Actが適用されるかどうかも確認しておく価値があります。CRAガイドで対象範囲と期限を解説しています。