<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=2109257909350072&amp;ev=PageView&amp;noscript= 1">

サプライチェーンセキュリティ

Trivy サプライチェーン攻撃(第2波・3/19発生):FutureVuls 影響調査レポート

目次

※2026/03/25(水)「GitHub Actions・Docker Hub・npm・PyPIに波及:Trivyサプライチェーン攻撃の影響確認ガイド」を追加で公開しています。  


注意: 本レポートは 2026年3月22日 23:00 JST(14:00 UTC)時点の情報に基づく。本インシデントは調査が続いており、情報が更新される可能性がある。最新の状況は Aqua Security の公式アドバイザリ(https://github.com/aquasecurity/trivy/security/advisories/GHSA-69fq-xp46-6x23 )を参照されたい。


1. Trivy サプライチェーン攻撃(第2波・3/19発生)調査結果

2026年3月19日、Trivy に対する2回目のサプライチェーン攻撃が発生した。本攻撃は2026年2月28日の初回攻撃で窃取されたクレデンシャルを利用した再攻撃であり、初回のクレデンシャルローテーションが不完全であったことが根本原因とされる。

調査の結果、FutureVuls が配布する Trivy バイナリ、FutureVuls の CI/CD パイプライン、npm 依存関係、および OSS の vuls リポジトリ( https://github.com/future-architect/vuls )のいずれについても、本攻撃による影響がないことを確認した。

なお、vuls リポジトリでは攻撃ウィンドウ中に Dependabot が v0.69.4 を検出したログが残っていたため、詳細な調査を実施した。その過程と結論は本記事の4.OSS vuls リポジトリへの影響調査に記録している。


2. Trivy サプライチェーン攻撃(第2波・3/19発生)の概要

2.1 参照した情報源

情報源 URL
Aqua Security 公式アドバイザリ (GHSA-69fq-xp46-6x23) https://github.com/aquasecurity/trivy/security/advisories/GHSA-69fq-xp46-6x23
StepSecurity 分析(第1回攻撃) https://www.stepsecurity.io/blog/hackerbot-claw-github-actions-exploitation
Aikido Security 技術分析(CanisterWorm) https://www.aikido.dev/blog/teampcp-deploys-worm-npm-trivy-compromise
Wiz 技術分析 https://www.wiz.io/blog/trivy-compromised-teampcp-supply-chain-attack
FutureVuls 初回攻撃レポート(2/28 攻撃分) https://www.vuls.biz/blog/trivy-supplychain-report

注意: 第1回攻撃(2/28)に関する公式インシデント報告として公開されていた Discussion #10265( https://github.com/aquasecurity/trivy/discussions/10265 )は削除されている。現在は Discussion #10420( https://github.com/aquasecurity/trivy/discussions/10420 )にて、第1回・第2回攻撃を統合した形でインシデントの経緯が説明されている。

2.2 攻撃ベクター

公式アドバイザリ(GHSA-69fq-xp46-6x23)に基づく攻撃対象は以下の3つ。

コンポーネント
攻撃内容
Exposure Window (UTC)
持続時間
trivy v0.69.4
悪意あるリリースの新規作成
(タイポスクワットドメイン(正規ドメインに酷似した偽ドメイン。
本件では securitysecurtiy と i/t を入れ替えたドメインが使用された)からのマルウェアのダウンロード)
2026-03-19 18:22 〜 ~21:42
約3時間
trivy-action
77タグ中76タグを credential stealer に force-push
(Runner.Worker プロセスメモリダンプ、50以上のファイルパスからの秘密情報窃取、
AES-256-CBC + RSA-4096 暗号化による持ち出し)
2026-03-19 ~17:43 〜 2026-03-20 ~05:40
約12時間
setup-trivy
全7タグを同一の infostealer に force-push
2026-03-19 ~17:43 〜 ~21:44
約4時間

2.3 第1回攻撃との関係

公式アドバイザリの記載を以下に引用する。

クレデンシャルローテーションは実施されたが、アトミックではなかった(全クレデンシャルが同時に無効化されなかった)。攻撃者はローテーション期間中に有効なトークンを使用して、新たに回転されたシークレットを窃取し、アクセスを維持した可能性がある。

("credential rotation was performed but was not atomic (not all credentials were revoked simultaneously). The attacker could have use a valid token to exfiltrate newly rotated secrets during the rotation window (which lasted a few days).")

2.4 npm への波及(CanisterWorm)

公式アドバイザリの対象範囲外であるが、Aikido Security の分析によると、攻撃は npm エコシステムへ波及し、自己増殖型ワーム「CanisterWorm」として以下のパッケージが侵害された。

  • @EmilGroup スコープの28パッケージ(後続 Wave で計44パッケージに拡大)
  • @opengov スコープおよび関連パッケージ計16件
  • @teale.io/eslint-config
  • @airtm/uuid-base32
  • @pypestream/floating-ui-dom
  • @leafnoise/mirage(Endor Labs が追加発見)

CanisterWorm の技術的詳細・対象パッケージの完全なリスト・IOC については、以下の各分析記事を含め、最新情報を参照されたい。本インシデントは調査が続いており、追加の侵害パッケージが表面化する可能性がある。

FutureVuls の npm 依存関係に対する CanisterWorm の影響調査はセクション 3.3 を参照されたい。


3. FutureVuls への影響調査

3.1 配布中の Trivy バイナリ

FutureVuls が現在配布中の Trivy バージョンは v0.69.3 である。

- リリースノート:https://help.vuls.biz/releasenotes/20260300_hotfix/#2026-03-12-%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E5%86%85%E5%AE%B9
- v0.69.3はGitHubのImmutable Releases機能(3月3日、v0.69.3 公開前に有効化済み)により保護されており、攻撃対象のv0.69.4とは異なる。

結論: 影響なし。

3.2 CI/CD パイプラインの確認

FutureVuls の CI/CD パイプラインでは aquasecurity/trivy-action および aquasecurity/setup-trivy使用していない。したがって、trivy-action のタグハイジャック攻撃および setup-trivy のリリース置換攻撃の影響を受ける経路が存在しない。

さらに、攻撃ウィンドウ(全コンポーネント合成: 2026-03-19T17:43:00Z 〜 2026-03-20T05:40:00Z)における CI/CD パイプラインの実行状況を確認した。

以下のコマンドで、任意のリポジトリの攻撃ウィンドウ内の CI 実行を確認できる。

    

# 攻撃ウィンドウ内の CI 実行を確認
gh run list \
  --repo <org>/<repo> \
  --created "2026-03-19T17:42:00Z..2026-03-20T05:41:00Z"

 

FutureVuls の各リポジトリで上記コマンドを実行した結果、いずれも no runs found(攻撃ウィンドウ内に CI/CD 実行なし)であった。

結論: 影響なし。

3.3 npm 依存関係(CanisterWorm)

CanisterWorm の対象パッケージ(セクション 2.4 参照。6スコープ・合計約60件)との依存関係を確認した。

以下のコマンドで、任意のプロジェクトの依存関係ファイルに対して CanisterWorm 対象パッケージの有無を一括確認できる。

    # CanisterWorm 対象パッケージの一括検索
# 対象ファイルは環境に応じて選択(package-lock.json / yarn.lock / pnpm-lock.yaml)
grep -iE \
  "@emilgroup/|@opengov/|@teale\.io/|@airtm/|@pypestream/|@leafnoise/|jest-preset-ppf|babel-plugin-react-pure-component|eslint-config-service-users|opengov-k6-core|cit-playwright-tests|react-leaflet-marker-layer|react-leaflet-cluster-layer|eslint-config-ppf" \
  package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null

 

FutureVuls の各リポジトリの依存関係ファイルに対して上記コマンドを実行した結果、いずれの CanisterWorm 対象パッケージにもマッチしなかった。

結論: 影響なし。


4. OSS vuls リポジトリへの影響調査

4.1 攻撃ウィンドウ内の CI 実行

vuls リポジトリ( https://github.com/future-architect/vuls )では攻撃ウィンドウ内に複数の CI 実行が存在した。全実行のログを侵害コンポーネントのキーワードで一括走査した。

    # 攻撃ウィンドウ内の全 CI 実行ログを侵害コンポーネントで一括走査
for id in $(gh run list \
  --repo future-architect/vuls \
  --created "2026-03-19T17:42:00Z..2026-03-20T05:41:00Z" \
  --json databaseId \
  --jq '.[].databaseId'); do
  echo "=== Run ID: $id ==="
  gh run view "$id" --repo future-architect/vuls --log 2>/dev/null | \
    grep -iE "trivy.*0\.69\.4|setup-trivy|trivy-action|emilgroup|opengov|teale\.io|airtm|pypestream" || \
    echo "  (not found)"
done

4.2 検出された Dependabot ジョブ

上記の走査により、Run ID 23322843048 において Dependabot が trivy v0.69.4 への更新を試みたことを検出した。他の全 Run は (not found) であった。

4.2.1 検出されたログ

    Dependabot  2026-03-20T00:03:22  INFO  Updating github.com/aquasecurity/trivy from 0.69.2 to 0.69.4
Dependabot  2026-03-20T00:04:08  POST /update_jobs/1285939927/create_pull_request
Dependabot  2026-03-20T00:04:08  204 /update_jobs/1285939927/create_pull_request
Dependabot  2026-03-20T00:04:09  Results:
            | created | github.com/aquasecurity/trivy ( from 0.69.2 to 0.69.4 ) |

4.2.2 ジョブの性質

vuls リポジトリの dependabot.yml では trivy 関連パッケージが独立したグループ(trivy)として管理されている。以下のコマンドで取得できる Run ID 23322843048 の全ログに基づき、このグループの Dependabot ジョブについて以下が判明した。

     gh run view 23322843048 --repo future-architect/vuls --log
  • "command":"recreate" — 新規作成ではなく既存 PR の再作成ジョブ
  • "updating-a-pull-request":true — 既存 PR の更新として実行
  • "existing-group-pull-requests" に trivy グループの既存 PR #2445(v0.69.3 への更新)が記録されていた
  • 「ターゲットバージョンが変更されたため、既存の Pull Request は supersede されるべきである("Target versions have changed, existing Pull Request should be superseded")」— Dependabot は v0.69.4 を検出し、既存 PR を supersede しようとした

4.3 影響の有無の確認

4.3.1 master ブランチの go.sum

GitHub API の contents エンドポイントは、ref パラメータ省略時にデフォルトブランチ(vuls リポジトリでは master)を返す。

     gh api repos/future-architect/vuls/contents/go.sum \
  --jq '.content' | base64 -d | grep "trivy.*v0.69.4"


出力なし — v0.69.4 は master ブランチに含まれていない。

4.3.2 Dependabot ブランチの内容

Dependabot が作成したブランチを以下のコマンドで検索し、trivy グループのブランチを特定した。

    gh api repos/future-architect/vuls/branches --paginate \
  --jq '.[] | select(.name | test("dependabot.*trivy")) | .name'

 

結果: dependabot/go_modules/master/trivy-75591bbe2f

このブランチの内容を確認した。

     gh api repos/future-architect/vuls/branches/dependabot/go_modules/master/trivy-75591bbe2f \
  --jq '{sha: .commit.sha, date: .commit.commit.committer.date, message: .commit.commit.message}'

 

結果:

  • コミット日時: 2026-03-19T02:25:48Z(攻撃開始の15時間前)
  • コミットメッセージ: from 0.69.2 to 0.69.3(v0.69.4 ではない)

さらに master との diff を確認した。

     gh api repos/future-architect/vuls/compare/master...dependabot/go_modules/master/trivy-75591bbe2f \
  --jq '.files[] | select(.filename == "go.mod" or .filename == "go.sum") | {filename, patch}'

 

go.mod の diff: v0.69.2 → v0.69.3(v0.69.4 ではない)

ブランチの内容は v0.69.3 への更新であり、v0.69.4 は含まれていない。

4.3.3 既存 PR #2445 の状態

セクション 4.2.2 の Job definition 内の "existing-group-pull-requests" に、trivy グループの既存 PR として PR #2445(v0.69.3)が記録されていた。この PR の現在の状態を確認した。

     gh pr view 2445 --repo future-architect/vuls \
  --json number,title,state,createdAt,closedAt,mergedAt,url,headRefName

 

結果:

  • タイトル: chore(deps): bump github.com/aquasecurity/trivy from 0.69.2 to 0.69.3 in the trivy group
  • 状態: OPEN(未マージ)
  • ブランチ: dependabot/go_modules/master/trivy-75591bbe2f

PR のタイトルは v0.69.3 のままであり、v0.69.4 への supersede は実際には反映されていない。

4.3.4 MERGED 済み PR の確認

     gh pr list --repo future-architect/vuls \
  --state all --author "app/dependabot" \
  --search "created:2026-03-19..2026-03-21" \
  --json number,title,state,createdAt,mergedAt

攻撃ウィンドウ前後で MERGED された Dependabot PR は以下の1件のみであった。

  • PR #2477: bump google.golang.org/grpc from 1.78.0 to 1.79.3(MERGED: 2026-03-19T02:24:13Z、攻撃開始の15時間前。trivy と無関係)

4.4 ログの created 表示と実際の PR/ブランチ不一致の説明

Dependabot updater の Results テーブルに「作成済み("created")」と記録されたにもかかわらず、実際のブランチ・PR には v0.69.4 が反映されなかった。この不一致について調査した。

4.4.1 Dependabot のアーキテクチャ

Andrew Nesbitt による dependabot-core の分析記事( https://nesbitt.io/2026/01/02/how-dependabot-actually-works.html )によると、dependabot-core はステートレスな Ruby ライブラリであり、実行間の状態を保持しない。スケジューリング、状態追跡、PR の実際の作成・管理などの調整ロジックは GitHub のプロプライエタリなインフラストラクチャ側で処理される。

同記事では、既存 PR のリフレッシュ時のジョブには「PR 更新中: true("updating-a-pull-request: true")」と対象パッケージのリストが含まれ、リフレッシュロジックは既存 PR の更新・クローズ・supersede を判断するが、そのクローズ理由は内部的に列挙されているものの PR メタデータには公開されない("The close reasons are enumerated internally ... but not exposed in the PR metadata")と記述されている。

つまり、updater コンテナが create_pull_request API を呼び出してログに「作成済み("created")」と記録する処理と、GitHub のインフラ側が実際にブランチを更新して PR を作成する処理は異なるレイヤーで動作しており、前者が成功しても後者が反映されないケースが存在する。

4.4.2 既知のバグとしての報告

「ログ上は作成済み("created")だが PR が作成/更新されない」現象は、dependabot-core の既知のバグとして、複数のエコシステムにまたがって広く報告されている。

Issue 報告日 エコシステム URL
#7542 2023年7月 Docker https://github.com/dependabot/dependabot-core/issues/7542
#7672 2023年7月 Docker https://github.com/dependabot/dependabot-core/issues/7672
#9199 2024年3月 Gradle https://github.com/dependabot/dependabot-core/issues/9199
#11657 2025年2月 GitHub Actions https://github.com/dependabot/dependabot-core/issues/11657
#11720 2025年3月 Ruby Bundler / JS https://github.com/dependabot/dependabot-core/issues/11720
#12224 2025年5月 Git Submodule https://github.com/dependabot/dependabot-core/issues/12224
#13879 2026年1月 pip/uv https://github.com/dependabot/dependabot-core/issues/13879
#14193 2026年2月 全エコシステム https://github.com/dependabot/dependabot-core/issues/14193

Issue #14193 では、この現象が以下のように明確に記述されている。

Dependabot updater が正常に実行を完了し、Results テーブルに「作成済み("created")」と表示するが、ブランチも PR も実際には作成されない。エラー報告はなく、ワークフローは成功ステータスで完了する。

("The run succeeds, the results table shows | created | ..., but no branches or PRs are created. This fails silently with no indication of the problem.")

4.5 vuls リポジトリの調査結論

Dependabot が攻撃ウィンドウ中(3/20 00:04 UTC)に Go モジュール github.com/aquasecurity/trivy の v0.69.4 を検出し、既存の v0.69.3 更新 PR(#2445)を supersede して v0.69.4 への更新を試みたことを CI ログから確認した。しかし、Dependabot updater の内部ログ上は「作成済み("created")」と記録されたものの、以下の4点から v0.69.4 はリポジトリに反映されていないことを確認した。

  1. master の go.mod / go.sum に v0.69.4 が存在しない
  2. Dependabot ブランチ(dependabot/go_modules/master/trivy-75591bbe2f)のコミット内容は v0.69.3 のまま(コミット日時: 攻撃開始15時間前の 3/19 02:25 UTC)
  3. 既存 PR #2445 のタイトルは「from 0.69.2 to 0.69.3」のまま変更なし、状態は OPEN(未マージ)
  4. 「作成済み("created")」表示と実際の PR/ブランチ不一致は dependabot-core の既知のバグ(#7542, #7672, #9199, #11657, #11720, #12224, #13879, #14193)

結論: vuls リポジトリへの影響なし。


5. 調査結果の全体像

調査対象 影響 根拠
FutureVuls 配布 Trivy バイナリ (v0.69.2) なし 攻撃対象は v0.69.4。v0.69.2 は初回レポートで安全性検証済み
FutureVuls CI/CD パイプライン なし trivy-action / setup-trivy 未使用。攻撃ウィンドウ内に CI/CD 実行なし
FutureVuls npm 依存関係(CanisterWorm) なし 各リポジトリの依存関係ファイルに対象パッケージ不在
vuls リポジトリ master ブランチ なし go.sum に v0.69.4 なし、MERGED PR に trivy 更新なし
vuls リポジトリ Dependabot ブランチ なし ブランチ内容は v0.69.3、ログ上の「作成済み」は既知バグ

6. 第1回攻撃からの変化点

項目 第1回(2/28) 第2回(3/19)
攻撃者 hackerbot-claw(Claude Opus 4.5 搭載 AI 自律型ボット)[^1] "TeamPCP" と見られる [^2]
攻撃手法 GitHub Actions ワークフロー脆弱性の悪用 → PAT 窃取 → リポジトリ乗っ取り 残存クレデンシャルの悪用 → 悪意あるリリース作成 + タグハイジャック
影響範囲 Trivy リポジトリ(GitHub Releases 削除、VSCode 拡張) Trivy バイナリ + GitHub Actions (trivy-action, setup-trivy) + npm 多数のパッケージ
対策の進展 Aqua Security が GitHub の Immutable Releases を 3/3 に有効化。v0.69.3 はこの機能により保護されている
("v0.69.3 is protected by GitHub's immutable releases feature (enabled March 3, before v0.69.3 was published)" — 公式アドバイザリ)

[^1]: StepSecurity の分析( https://www.stepsecurity.io/blog/hackerbot-claw-github-actions-exploitation )より

[^2]: "TeamPCP is suspected to be behind the attacks" — The Hacker News( https://thehackernews.com/2026/03/trivy-supply-chain-attack-triggers-self.html )。Wiz・Aikido Security・Cyble の各分析でも同一名称で言及されている(URL はセクション 7 参照)

注: Immutable Releases とは、有効化されたリリースの削除・変更・上書きを防止する GitHub の機能である。詳細は GitHub 公式ドキュメント( https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository#creating-a-release )を参照。


7. 参考リンク

攻撃に関する情報源

以下のうち、セクション 2.1 の情報源テーブルと重複するものには(※2.1掲載)を付記している。本セクションはレポート内の全リンクを一箇所で参照できるよう、意図的に網羅している。

FutureVuls 関連

Dependabot の既知バグに関する参考情報


付録: 読者が自身の環境で実施できる確認手順

以下のコマンドは、FutureVuls / vuls に限らず、Trivy を利用する任意のプロジェクトで応用可能である。

A.1 攻撃ウィンドウ内の CI 実行確認

    # GitHub CLI で攻撃ウィンドウ内の CI 実行を確認
gh run list \
  --repo <org>/<repo> \
  --created "2026-03-19T17:42:00Z..2026-03-20T05:41:00Z"

A.2 CI ログの一括走査

    # 侵害コンポーネントのキーワードで全ログを一括走査
for id in $(gh run list \
  --repo <org>/<repo> \
  --created "2026-03-19T17:42:00Z..2026-03-20T05:41:00Z" \
  --json databaseId \
  --jq '.[].databaseId'); do
  echo "=== Run ID: $id ==="
  gh run view "$id" --repo <org>/<repo> --log 2>/dev/null | \
    grep -iE "trivy.*0\.69\.4|setup-trivy|trivy-action|emilgroup|opengov|teale\.io|airtm|pypestream" || \
    echo "  (not found)"
done

A.3 Go プロジェクトの go.sum 確認

    # go.sum に v0.69.4 が含まれないことを確認
grep "trivy.*v0.69.4" go.sum

A.4 npm 依存関係の CanisterWorm 対象パッケージ確認

    # package-lock.json / yarn.lock / pnpm-lock.yaml を対象に一括検索
grep -iE \
  "@emilgroup/|@opengov/|@teale\.io/|@airtm/|@pypestream/|@leafnoise/|jest-preset-ppf|babel-plugin-react-pure-component|eslint-config-service-users|opengov-k6-core|cit-playwright-tests|react-leaflet-marker-layer|react-leaflet-cluster-layer|eslint-config-ppf" \
  package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null

 

A.5 ファイルシステム上の感染痕跡確認

    # CanisterWorm の永続化痕跡を確認
ls -la ~/.local/share/pgmon/service.py 2>/dev/null
ls -la ~/.config/systemd/user/pgmon.service 2>/dev/null
ls -la /tmp/pglog 2>/dev/null
ls -la /tmp/.pg_state 2>/dev/null

# systemd サービスの確認
systemctl --user status pgmon.service 2>/dev/null

A.6 GitHub Organization 上の窃取データリポジトリ確認

trivy-action の credential stealer は、窃取データの送信に失敗した場合のフォールバックとして、被害者の GitHub アカウントに tpcp-docs という名前のパブリックリポジトリを作成し、リリースアセットとしてデータをアップロードする。

    # Organization 内に tpcp-docs リポジトリが存在しないことを確認
gh repo view <org>/tpcp-docs 2>/dev/null && echo "WARNING: found" || echo "OK: not found"

 

執筆者プロフィール

writer-icon

フューチャー株式会社

Cyber Security Innovation Group エンジニア

棚井龍之介(たない りゅうのすけ)

役割

セキュリティ領域を専門とするエンジニア(クラウドインフラ領域、バックエンド開発 )として業務に従事。同社が展開する脆弱性管理ツール「FutureVuls」に深く携わっており、OSSの脆弱性スキャナ(TrivyやVuls)のエンジン検証、SBOMの取り込み、サプライチェーン攻撃の調査・安全性の検証レポートなどを担当。

略歴

フューチャー株式会社の公式技術ブログ「Future Tech Blog」や「FutureVuls Blog」で継続的に技術発信を行っており、クラウドインフラからサイバーセキュリティまで幅広い技術領域で活躍。

  • サイバーセキュリティ: 脆弱性管理(CPE名の検索最適化など)、サプライチェーンセキュリティの監視、セキュリティ製品の実装・運用

  • クラウド・インフラストラクチャ: AWS(DynamoDB等のサーバレス技術)、Terraformを用いたInfrastructure as Code(IaC)の推進、LocalStackを利用したローカルテスト環境の構築。

  • 業務自動化とプログラミング: 主な使用言語はGo言語やRuby。GAS(Google Apps Script)やSlack Botを利用した業務効率化、Seleniumを利用したUI操作の自動化。

 

この記事をシェアする