Share
Embed
Transcript
205 slides
-
この講演を作った動機 やパッケージレジストリを経由する侵害が続いている。 個々の対応策は公開されているが、開発ワークフロー全体を通してまとめた資料が少ない。 GitHub Actions tjactions/changedfiles 2025 3 ( 月)
年 Nx s1ngularity 2025 8 ( 年 月) ワークフローへのコマンド 注入で npm トークンが盗 まれ、汚染版が端末の資格 Action の全タグが不正コミ ットへ付け替えられ、ラン 情報を AI エージェントに ナーのメモリから読み出さ 探索させた。 れたシークレットが公開ロ グに出た。 ( Shai-Hulud 2025 9 年 月) ( Trivy 2026 月) 年3 のワーム。 trivy-action のほぼ全タグ postinstall で秘密情報を盗 が強制更新され、下流のプ み、盗んだトークンで他の ロジェクトのランナーの資 パッケージへ自己増殖し 格情報が流出した。 た。 npm 3 -
この講演で渡すもの やるべきことを 80 項目に集めた。 開発者の作業順の分類と、全体に通底する原則を添える。 80 の項目 やるべきことの一覧。各項目に概 要と対応を付け、後から自分の環 境と照らして点検できる形にす
る。 4 つのフェーズ 書く、取り込む、ビルドする、届 ける。開発者の作業の順に並べ、 各項目の置き場にする。 4 つの原則 フェーズをまたいで繰り返し現れ る考え方。各項目に、どの原則の 実装かを付記する。 4 -
前提 この講演は次のことを前提とする。 作るソフトウェアそのもののセキュリティは扱わない。 内容は特定の CI ツールや実行環境に依らない。 ただし、説明のために具体的な製品名を使う。 例示の CI ツールは
GitHub Actions とする。 レジストリは npm、PyPI、Docker Hub、クラウドは AWS を例にする。 対応の実装例として OSS や製品を紹介することがある。 5 -
のサプライチェーン攻撃 Trivy のサプライチェーン攻撃(2026 年 3 月)では、Trivy への 4 段階の遂行が LiteLLM
への仕込みになった。 Trivy フォークから 細⼯した PR を送る PR のコードが、本家の 権限で実⾏される コードを仕込む コードを動かす 汚染版の Trivy が LiteLLM の CI に取り込まれる の CI で 汚染版が実⾏される コードを仕込む LiteLLM コードを動かす aqua-bot の PAT 資格情報を盗む PyPI の公開トークン 資格情報を盗む 盗んだ PAT で 汚染版の Trivy を公開 ⽬的を遂⾏する LiteLLM PyPI の汚染版を に公開 ⽬的を遂⾏する 9 -
つの原則 通底する原則は、次の 4 つである。 4 原則 1 2 3 4
出所と内容の検証 実行されるコードの把握 盗まれる前提の資格情報 侵害後の手順の事前設計 内容 依存関係、コードの変更、成果物を、受け入れる前に出所と内容 で確かめる 何が実行されるかを把握し、動かすものを自分で決める 短命、最小範囲、実行主体ごとに作る 被害範囲、検知、失効と復旧の順序を事前に決める 10 -
経路と原則の対応 4 つの原則は、攻撃者の 4 段階にそれぞれ対応する。 コードを仕込む コードを動かす 資格情報を盗む ⽬的を遂⾏する 原則
1 原則 2 原則 3 原則 4 出所と内容の検証 実⾏される コードの把握 盗まれる前提の 資格情報 侵害後の⼿順の 事前設計 11 -
つのフェーズ 開発者の作業を 4 つのフェーズに分け、フェーズごとにやるべきことを列挙する。 4 章 1 2 3 4
フェーズ 書く 取り込む ビルドする 届ける 範囲 リポジトリをクローンしてから、変更を push するまで 変更がリポジトリに届いてから、main ブランチにマージされるまで ワークフローが起動してから、成果物ができるまで 成果物ができてから、リリースするまで 12 -
LiteLLM 2026 の汚染版 年 3 月 24 日に PyPI へ公開された汚染版は、開発者の端末で次のように動いた。
取り込み に 1.82.7、10:52 UTC に 1.82.8 が公開され、報 告から約 3 時間で PyPI が削除 した。この間の pip install や 依存の更新で端末に入った 10:39 UTC 実行 収集と送信 は proxy_server の import 時、1.82.8 は wheel 内の .pth で Python の起動時 に動いた(import 不要) 環境変数、SSH 鍵、クラウド と DB の資格情報、各種トーク ン、LLM の API キーなどを集 め、AES-256-CBC と RSA4096 で暗号化して models.litellm[.]cloud へ送信 した 1.82.7 永続化 以外では、systemd のユー ザーユニット (Restart=always)として残 った CI 出典 Datadog Security Labs: https://securitylabs.datadoghq.com/articles/litellm-compromised-pypi-teampcp-supply-chain-campaign/ Trend AI Security: https://www.trendaisecurity.com/en-us/resources-insights/trendai-security-blog/inside-litellm-supply-chain-compromise BerriAI/litellm issue #24518: https://github.com/BerriAI/litellm/issues/24518 15 -
Nx s1ngularity 2025 年 8 月 26 日に npm へ公開された汚染版は、開発者の端末で次のように動いた。
取り込み 月 26〜27 日の約 4 時間、 nx と @nx/* の汚染版が公開さ れていた。VS Code の Nx Console は nx@latest を自動 で入れるので、エディタを開く だけで入った 8 出典 Nx 実行 探索と収集 公開と妨害 が telemetry.js を 実行した。Linux と macOS で のみ動いた 端末の Claude Code、Gemini CLI、Amazon Q を承認なしの フラグで起動し、トークンや SSH 鍵、.env、クラウドの資 格情報を探させた 被害者の GitHub トークンで被 害者自身のアカウントに公開リ ポジトリを作り、集めた情報を 約 8 時間公開した。シェルの 設定ファイルに shutdown を 追記した postinstall のアドバイザリ: https://github.com/nrwl/nx/security/advisories/GHSA-cxm3-wv7p-598c Wiz: https://www.wiz.io/blog/s1ngularity-supply-chain-attack 16 -
「書く」の項目 「書く」でやるべきことは、次の 18 項目である。 重⼤度 ⾼ 1 インストール時に⾛るスクリプトを⽌める 2 公開直後のバージョンを採⽤しない猶予期間を置く
3 社内パッケージの取得先をレジストリの設定で固定する 4 依存関係の解決結果をロックファイルで固定する 5 リポジトリを IDE で開いたときの⾃動実⾏を⽌める 6 AI エージェントの承認確認を無効にしない 7 本⼈のアカウントをフィッシング耐性のある MFA で守る 8 ⻑期の資格情報を端末に置かない 9 IDE 拡張を許可した発⾏元のものに限定する 10 依存関係の取り込み経路を承認されたレジストリに限定する 11 MCP サーバーを許可した発⾏元のものに限定する 重⼤度 中 12 秘密情報をコミットする前に⽌める 13 コミットに署名する 14 AI エージェントが読み書きできるファイルを限定する 15 AI エージェントの外向き通信を許可リストに制限する 16 AI エージェントに専⽤の ID を使う 17 ログインセッションを短命にする 18 端末上の資格情報の⼀覧と失効⼿順を持つ 17 -
インストール時に走るスクリプトを止める の postinstall のように、依存を入れただけで任意のコードが動く仕組みを、ワー ムは増殖に使う。 npm install 原則 実行されるコードの把握 侵害例
(2025 年 9 月): postinstall で秘密情報を盗み、他のパッケージへ自己増殖した Shai-Hulud https://www.wiz.io/blog/shai-hulud-npm-supply-chain-attack (2025 年 11 月): preinstall で Bun を入れてペイロードを実行した Shai-Hulud 2.0 https://securitylabs.datadoghq.com/articles/shai-hulud-2.0-npm-worm/ (2026 年 3 月): コードから参照されない依存の postinstall でペイロードを実行した Axios https://github.com/axios/axios/issues/10636 18 -
インストール時に走るスクリプトを止める 対応 以降は、依存のインストール時スクリプトが既定で走らない npm approve-scripts で、実行を許す依存を個別に許可する npm 11 以前は .npmrc
に ignore-scripts=true を置く リポジトリの .npmrc に置けば CI でも有効になる pnpm 10 以降は既定で止まる pnpm 10.26 以降は allowBuilds で許可する Python でインストール時に動くのは sdist のビルドで、pip の --only-binary :all: か uv の --nobuild で止める npm 12 19 -
公開直後のバージョンを採用しない猶予期間を置く 汚染版は、公開から数時間で取り下げられることが多い。 猶予期間の間に取り下げられた汚染版は、インストールの候補に入らない。 原則 出所と内容の検証 侵害例 (2025 年 9 月):
汚染版は公開から約 2 時間で取り下げられた chalk / debug https://www.wiz.io/blog/widespread-npm-supply-chain-attack-breaking-down-impact-scope-across-debug-chalk (2026 年 3 月): 汚染版は公開から約 3 時間で削除された Axios https://github.com/axios/axios/issues/10636 (2026 年 3 月): 1.82.7 と 1.82.8 は公開当日のうちに PyPI から削除された(報告から約 3 時間) LiteLLM https://securitylabs.datadoghq.com/articles/litellm-compromised-pypi-teampcp-supply-chain-campaign/ 20 -
公開直後のバージョンを採用しない猶予期間を置く 対応 以降は .npmrc に min-release-age を日数で置く pnpm 10.16 以降は
minimumReleaseAge を分で設定する pnpm 11 は既定で 1440 分になる Bun は bunfig.toml の [install] minimumReleaseAge を秒で設定する uv は exclude-newer に 7 days のような期間を置く 各ファイルのアップロード時刻で判定し、uv pip とプロジェクトの両方で有効になる 急ぎの修正は pnpm の minimumReleaseAgeExclude などで個別に外す npm 11.10 21 -
社内パッケージの取得先をレジストリの設定で固定する 社内パッケージの取得先を名前で固定していないと、同名の公開パッケージを取り込みうる。 攻撃者は、社内のパッケージ名を推測して公開レジストリに登録するだけでよい。 原則 出所と内容の検証 侵害例 (2021 年 2 月):
研究者の Alex Birsan が内部パッケージ名を公開レジストリに登録し、35 社 超の端末やビルド環境でコードを実行した dependency confusion https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610 22 -
社内パッケージの取得先をレジストリの設定で固定する 対応 は .npmrc に @myorg:registry=https://... を置き、スコープごとにレジストリを固定する スコープのない名前は既定のレジストリに向く pip は
--extra-index-url を使わない 全ての index を優先順位なしに探し、高いバージョンを選ぶため index は --index-url の 1 つにし、公開パッケージは社内 index を経由して取る uv は既定の first-index により、最初に見つかった index だけからパッケージを取る [[tool.uv.index]] の explicit = true と tool.uv.sources で index を固定する npm 23 -
依存関係の解決結果をロックファイルで固定する バージョン範囲で指定した依存は、解決のたびに違うものへ変わりうる。 ロックファイルは解決したバージョンとハッシュを記録し、次のインストールでは範囲を解決 し直さない。 原則 出所と内容の検証 侵害例 (2018 年 11
月): event-stream 3.3.6 に汚染版の flatmap-stream 0.1.1 が依存として加えられ、バー ジョン範囲で指定していた利用者に入った event-stream https://github.com/dominictarr/event-stream/issues/116 24 -
依存関係の解決結果をロックファイルで固定する 対応 ロックファイル(package-lock.json、pnpm-lock.yaml、uv.lock など)をコミットする pip は requirements にハッシュを付け、--require-hashes でインストールする Dockerfile
の FROM はタグではなくダイジェスト(@sha256:...)で指定する Terraform は .terraform.lock.hcl をコミットする 固定されるのはプロバイダだけで、モジュールはバージョン固定か git のコミット SHA で参照する Go は go.sum をコミットする 25 -
リポジトリを IDE で開いたときの自動実行を止める リポジトリ内の設定ファイルに書かれたタスクやフックは、開発者がクローンしてエディタや AI エージェントで開き、信頼した時点で実行される。 原則 実行されるコードの把握 侵害例 (2026
年 6 月): Microsoft の Azure 組織のリポジトリに .claude/settings.json のフックと VS Code のタス クを仕込み、開いた端末でスティーラーを起動させた Miasma https://www.stepsecurity.io/blog/miasma-worm-hits-microsoft-again-azure-functions-action-and-72-otherrepositories-disabled-after-supply-chain-attack-targeting-ai-coding-agents (2026 年 8 月): VS Code のタスクと .claude の設定を使い、GitHub のブランチへも感染を広げた ChainDrop https://securitylabs.datadoghq.com/articles/npm-worm-compromises-popular-npm-packages/ 26 -
リポジトリを IDE で開いたときの自動実行を止める 対応 は Workspace Trust を有効にし、信頼していないリポジトリは制限モードで開く AI エージェントのフォルダを信頼するかの確認を無効にしない
信頼はリポジトリ単位で永続するので、.claude/ などの設定の差分は pull のたびに見る 組織では Claude Code の managed settings(管理者が配布し、利用者が上書きできない設定)に allowManagedHooksOnly: true を置く Claude Code を対話なしで実行するときは --bare か --settings '{"disableAllHooks": true}' でフ ックを止める VS Code 27 -
AI エージェントの承認確認を無効にしない 攻撃者は、AI エージェントが読むリポジトリの中身や Web ページに命令を書き込める。 承認なしモードでは、入力に書かれた命令も、マルウェアが起動した AI エージェントの操作 も、人の確認なしに実行される。
原則 実行されるコードの把握 侵害例 (2025 年 8 月): マルウェアが承認なしのフラグで Claude Code、Gemini CLI、Amazon Q を起動 し、端末の秘密情報を探索させた Nx s1ngularity https://www.wiz.io/blog/s1ngularity-supply-chain-attack 28 -
AI エージェントの承認確認を無効にしない 対応 承認なしで動かすのは、端末から隔離した devcontainer などの専用環境に限る 管理者が配布し、利用者が上書きできない設定で、承認なしモードを無効にする Claude Code は
permissions.disableBypassPermissionsMode を "disable" にする MDM の managed-settings.json で配る。Team と Enterprise なら claude.ai コンソールか らも配れる Gemini CLI はシステム設定ファイルで security.disableYoloMode を有効にする 29 -
本人のアカウントをフィッシング耐性のある MFA で守る 開発者本人の GitHub、npm、クラウドのアカウントが乗っ取られると、全フェーズの権限が そのまま攻撃者に渡る。 TOTP(認証アプリのワンタイムコード)は、偽サイトが中継すればそのまま使われる。 原則 盗まれる前提の資格情報 侵害例
(2025 年 9 月): npmjs.help のドメインから 2FA の更新を求めるメールを送り、偽サイトで認証情報を 入力させてメンテナのアカウントを乗っ取った chalk / debug https://www.aikido.dev/blog/npm-debug-and-chalk-packages-compromised 30 -
本人のアカウントをフィッシング耐性のある MFA で守る 対応 と npm でパスキーかセキュリティキーを登録し、ログインにはそれを使う GitHub では SMS
を 2FA から外す GitHub はパスキーだけの 2FA にできないので、TOTP は残したままパスキーを主に使う 組織の設定でメンバーの 2FA を必須にし、Only allow secure two-factor methods で SMS を無効 にする GitHub 31 -
長期の資格情報を端末に置かない ~/.aws/credentials や ~/.npmrc のトークン、.env、~/.ssh の秘密鍵は、端末で動くすべてのプロセ スから読める。 2025 年以降の端末を狙った侵害の多くが、これらを集めている。 原則
盗まれる前提の資格情報 侵害例 ( 年 月) エージェントで端末の秘密情報と SSH 鍵を探索し、被害者の GitHub に公開した Nx s1ngularity 2025 8 : AI https://www.wiz.io/blog/s1ngularity-supply-chain-attack ( 年 月) 端末の と のトークンを集め、自己増殖と永続化に使った Shai-Hulud 2025 9 : npm GitHub https://www.wiz.io/blog/shai-hulud-npm-supply-chain-attack 社内リポジトリの流出( 件が取得されたとされる 年 月) 汚染された 拡張が社員の端末で資格情報を集め、社内リポジトリ約 GitHub 2026 5 : Nx Console 3800 https://github.blog/security/investigating-unauthorized-access-to-githubs-internal-repositories/ 32 -
長期の資格情報を端末に置かない 対応 は IAM Identity Center の aws sso login
で、短命な資格情報を使う npm は granular access token で範囲と期限を絞る GitHub は fine-grained PAT で期限と範囲を絞り、ランナー登録やワークフローの書き込みは許さな い SSH 鍵は FIDO 鍵にするか、使うたびに承認を求める agent 経由で使う git の資格情報は OS のキーチェーンの credential helper に保存し、平文ファイルに置かない 長期の鍵が必要なら OS のキーチェーンや 1Password の CLI 連携から渡し、ファイルに置かない AWS 33 -
IDE 拡張を許可した発行元のものに限定する 拡張は、開発者と同じ権限で動くコードであり、誰でも公開でき、自動で更新される。 自動更新は、正規の発行元の拡張が汚染版に更新された場合もそのまま端末に入れる。 IDE 原則 出所と内容の検証 侵害例 (2025 年
10 月): Open VSX の既存の拡張に不可視文字でコードが仕込まれ、盗んだ資格情報で他の拡張 GlassWorm へ広がった https://www.aikido.dev/blog/glassworm-returns-unicode-attack-github-npm-vscode 34 -
IDE 拡張を許可した発行元のものに限定する 対応 組織では、VS Code のポリシーで許可リストと自動更新の停止を配る AllowedExtensions ポリシーで extensions.allowed を配り、発行元か拡張
ID の許可リストに する 一覧にない拡張はインストールできず、後から一覧を外れた拡張は無効になる ExtensionsAutoUpdate ポリシーで extensions.autoUpdate を無効にする 個人では、拡張を棚卸しして数を減らし、発行元を確認する extensions.autoUpdate を false にし、更新は内容を確認して手動で入れる 35 -
MCP サーバーを許可した発行元のものに限定する ( )サーバーは AI エージェントにツールを渡すプログラムで、手元で動 くものは端末の権限を持つ。 ツールの説明文は命令として読まれるので、発行元を確かめずに入れたサーバーは AI エージェントを
操れる。 MCP Model Context Protocol 原則 出所と内容の検証 侵害例 ( 年 9 月): Postmark 公式を装った非公式の MCP サーバーが、15 バージョンを正常に公開した後、1.0.16 で送信メールをすべて外部へ Bcc した postmark-mcp 2025 https://snyk.io/blog/malicious-mcp-server-on-npm-postmark-mcp-harvests-emails/ の ( 年 月) 信頼していないリモート MCP サーバーへの接続で、authorization_endpoint の URL か コマンドが注入された mcp-remote RCE 2025 7 : OS https://github.com/advisories/GHSA-6xpm-ggf7-wc3p ら 38 -
MCP サーバーを許可した発行元のものに限定する 対応 組織では、Claude Code の managed settings で MCP
サーバーの許可リストを配る allowedMcpServers と allowManagedMcpServersOnly: true を組にして、利用者が自分の設 定で広げられなくする deniedMcpServers で既知の不正なサーバーを止める 配布は MDM のほか、claude.ai の管理コンソールからもできる 個人では、発行元を確認したサーバーだけを設定し、リモートのサーバーは接続前に確認する ツール定義のハッシュを記録し、更新での差分を検知する AI エージェントのスキルとプラグインも同じ対象にする 39 -
コミットに署名する なりすましコミットは、他人の名前とメールを入れるだけで作れる。 署名があれば、本人のコミットと区別できる。 原則 出所と内容の検証 侵害例 のサプライチェーン攻撃(2026 年 3 月):
メンテナの名前と日時を写したなりすましコミットが作られ、trivyaction のタグがそこへ向けられた Trivy https://snyk.io/articles/trivy-github-actions-supply-chain-compromise/ 43 -
コミットに署名する 対応 で gpg.format=ssh、user.signingkey、commit.gpgsign=true を設定し、GitHub に 署名鍵として登録する GitHub の vigilant
mode を有効にし、自分名義の未署名コミットに Unverified を表示させる git config 44 -
AI エージェントが読み書きできるファイルを限定する エージェントが読むファイル、Web ページ、MCP の応答は、すべて命令になりうる。 読み書きできるファイルを絞れば、命令を注入されても資格情報は読めず、次回の起動を変える 設定も書けない。 AI 原則 実行されるコードの把握
侵害例 (2025 年 4 月): Invariant Labs が、ツール説明文に隠した命令で AI エージェントに ~/.ssh/id_rsa を 読ませ、ツールの引数として送らせることを実証した tool poisoning https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks 45 -
AI エージェントが読み書きできるファイルを限定する 対応 か Anthropic Sandbox Runtime(srt)などのサンドボックスで動かす 資格情報ファイル(~/.aws、~/.ssh、.env)を読ませない devcontainer は端末からマウントしない
srt は denyRead で拒否する Claude Code は sandbox.credentials で拒否する 設定ファイル(.git/hooks、.mcp.json、.claude/)への書き込みは、srt と Claude Code が既定で 常に拒否する devcontainer 46 -
AI エージェントの外向き通信を許可リストに制限する 対応 サンドボックスで外向き通信を許可リストにする devcontainer は iptables で許可した宛先以外を遮断する srt は
allowedDomains 以外を既定で拒否する Claude Code は sandbox.network.allowedDomains と strictAllowlist: true で未列挙の宛先 を遮断する 48 -
AI エージェントに専用の ID を使う エージェントは、既定で開発者の権限を継承する。 専用の ID(identity)と短命なトークンを渡せば、命令を注入されても被害はその ID の権限の 範囲に留まる。
AI 原則 盗まれる前提の資格情報 侵害例 のプロンプトインジェクション(2025 年 5 月): 公開 Issue の命令で、AI エージェントが利用者のトーク ンで非公開リポジトリを読み、公開 PR に書き出した GitHub MCP https://invariantlabs.ai/blog/mcp-github-vulnerability (2026 年 2 月): Codespaces の Copilot が Issue の HTML コメントの命令を読み、GITHUB_TOKEN がジョブに自動で渡すトークン)を漏らした RoguePilot Actions ( https://thehackernews.com/2026/02/roguepilot-flaw-in-github-codespaces.html 49 -
AI エージェントに専用の ID を使う 対応 エージェントには本人のトークンを渡さず、専用の fine-grained PAT を期限とリポジトリと権限 を絞って発行する
トークンは AI エージェントに渡さず、プロキシの MCP サーバーに持たせる プロキシは専用 ID のトークンで GitHub に接続し、AI エージェントに公開するツールを絞る プロキシは AI エージェントとは別のユーザー、コンテナ、ホストのいずれかで動かし、HTTP で公 開する FastMCP の create_proxy で作れる。上流の GitHub MCP サーバーへ専用 ID のトークンで接続 し、HTTP で公開する AI 50 -
ログインセッションを短命にする を通過した後のセッションも資格情報であり、盗まれれば再認証なしに使われる。 有効期間が長いほど、盗まれたセッションが使える時間も長い。 MFA 原則 盗まれる前提の資格情報 侵害例 (2023 年 1
月): エンジニアの端末のマルウェアが MFA を通過した SSO セッションを盗み、攻撃者がそのセ ッションで顧客の秘密情報を持ち出した CircleCI https://circleci.com/blog/jan-4-2023-incident-report/ (2023 年 10 月): サポートケースに添付された HAR ファイル(ブラウザの通信記録)から、セッショントークン が盗まれた Okta https://sec.okta.com/articles/2023/11/unauthorized-access-oktas-support-case-management-system-rootcause 51 -
ログインセッションを短命にする 対応 ( 、 など)でセッションの有効期間を短くする 管理操作と本番操作に、再認証を要求する 端末に束縛されたセッション(Okta の Device-Bound SSO
など)が使えるなら使う IdP Okta Entra ID 52 -
端末上の資格情報の一覧と失効手順を持つ 端末には、クラウド、GitHub、npm、SSH の資格情報が散在する。 一覧がなければ失効に漏れが出て、順序を誤れば端末のデータを失う。 原則 侵害後の手順の事前設計 侵害例 (2026 年 5
月): 常駐プロセスがトークンの失効を検知するとホームディレクトリを消す作りで、除去より先 に失効させると端末のデータを失う TanStack https://tanstack.com/blog/npm-supply-chain-compromise-postmortem (2025 年 11 月): 流出と増殖の両方に失敗すると(トークンの失効後など)、ホームディレクトリを消 Shai-Hulud 2.0 去した https://securitylabs.datadoghq.com/articles/shai-hulud-2.0-npm-worm/ 53 -
端末上の資格情報の一覧と失効手順を持つ 対応 、 、 、 、 、 、 ごとに、失効の手順と を書いておく
失効の順序を決めておく 端末をネットワークから切り離し、常駐プロセスを除去する 失効と再発行は侵害された端末では行わず、信頼できる別の端末から各サービスの管理画面で行う ~/.aws ~/.npmrc ~/.config/gh ~/.ssh ~/.docker ~/.kube .env URL 54 -
「取り込む」の範囲 開発者の push した変更が、PR、レビュー、マージを経て main ブランチに入るまで を扱う。 リポジトリ push PR
レビュー 承認 マージ main 開発者 56 -
のサプライチェーン攻撃 2026 年 3 月 19 日、Trivy のリポジトリには、レビューを経ずに次のようにコードが仕 込まれた。 Trivy
残存 なりすまし タグ push 月 1 日の復旧で資格情報を一 斉に失効させなかったため、 aquasecurity/trivy に push できるアクセスが残った メンテナの名前と過去の日付を 写した未署名のコミットで、リ リースワークフローの actions/checkout の参照を書 き換えた そのコミットはどのブランチに も属さず、17:43 UTC に v0.69.4 のタグだけが push さ れてリリースワークフローが起 動した 3 出典 GitHub 公開 、書き換えられたワ ークフローで作られた汚染版 v0.69.4 が公開された 18:22 UTC アドバイザリ: https://github.com/aquasecurity/trivy/security/advisories/GHSA-69fq-xp46-6x23 Wiz: https://www.wiz.io/blog/trivy-compromised-teampcp-supply-chain-attack 57 -
「取り込む」の項目 「取り込む」でやるべきことは、次の 21 項目である。 重⼤度 ⾼ 19 依存関係の更新 bot に猶予期間を置く
20 秘密情報の push をリポジトリ側で拒否する 21 main ブランチへの変更にレビューを必須にする 22 古いブランチに残ったワークフローを削除する 23 タグとリリースを書き換えられなくする 24 履歴に残った秘密情報を失効させる 25 CI を起動できる主体と条件を限定する 重⼤度 中 26 依存関係を継続的に更新する 27 ⾃動実⾏される設定ファイルの変更に所有者の承認を必須に 28 バイナリのコミットを禁⽌する 29 コミット署名を必須にする 30 依存関係の健全性を継続的に監視する 31 組織の基本権限を最⼩にする 32 連携 App の権限を最⼩にする 33 bot の承認をマージ要件に数える範囲を限定する 34 リポジトリを組織の外へ出せる操作を制限する 35 隠し⽂字を lint で検出する 36 AI エージェントが⽣成した PR の受け⼊れ条件を決める 37 ⼈と bot と App の権限を定期的に棚卸しする 38 監査ログのイベントに通知を付ける 39 リポジトリと連携先の失効⼿順を持つ 58 -
依存関係の更新 bot に猶予期間を置く 依存関係を自動で更新する bot を使っている場合、公開直後のバージョンがそのまま PR で提 案される。 猶予期間を設定すれば、公開から数時間で取り下げられる汚染版を自動で避けられる。
原則 出所と内容の検証 侵害例 (2025 年 9 月): 汚染版は公開から約 2 時間で取り下げられた chalk / debug https://www.wiz.io/blog/widespread-npm-supply-chain-attack-breaking-down-impact-scope-across-debug-chalk (2026 年 3 月): 汚染版は公開から約 3 時間で削除された Axios https://github.com/axios/axios/issues/10636 59 -
依存関係の更新 bot に猶予期間を置く 対応 は renovate.json に minimumReleaseAge: "3 days"
を置く 脆弱性修正の PR(vulnerabilityAlerts、GitHub のみ)は既定で猶予期間の対象外になる Dependabot は dependabot.yml の cooldown に default-days を置く cooldown は security updates には適用されず、脆弱性の修正は自動で例外になる Renovate 60 -
Dependabot は GitHub に組み込まれた依存関係の更新 bot で、dependabot.yml に書いた 対象を定期的に調べ、新しいバージョンへの PR を作る。
cooldown は、公開から指定した日数が経ったバージョンだけを候補にする設定である。 Dependabot 61 -
秘密情報の push をリポジトリ側で拒否する 対応 と push protection を有効にする 組織の設定で全リポジトリに一括で有効にする 非公開リポジトリでは
GitHub Secret Protection のライセンスが要る delegated bypass でバイパスできるロールとチームを限定する(Who can bypass push protection for secret scanning を Specific roles or teams にする) 既定では、書き込み権限を持つ全員がバイパスできる secret scanning 63 -
main ブランチへの変更にレビューを必須にする レビューが必須でないと、乗っ取られた正規アカウントや内部者が単独で main ブランチを変 えられる。 直接 push、強制 push、レビューなしのマージが対象になる。 原則
出所と内容の検証 侵害例 (2026 年 6 月): 侵害された貢献者のアカウントで、[skip ci] と日時の偽装を付けて直接 push された Miasma https://www.stepsecurity.io/blog/miasma-worm-hits-microsoft-again-azure-functions-action-and-72-otherrepositories-disabled-after-supply-chain-attack-targeting-ai-coding-agents 64 -
main 対応 ブランチへの変更にレビューを必須にする で PR を必須にし、承認を 1 名以上にする 規模に応じて承認者数を増やす rulesets
「Dismiss stale pull request approvals when new commits are pushed」を有効にする rulesets の Bypass list を空にし、Repository admin も入れない 強制 push とブランチの削除を禁止する rulesets は組織で定義して全リポジトリに継承させる 必須ステータスチェックをマージ要件に含める 65 -
古いブランチに残ったワークフローを削除する ワークフローはブランチごとにファイルとして残るので、main ブランチで直しても、古いブラ ンチのファイルはそのブランチを対象にした push や PR で動く。 直したはずの脆弱性は、そのブランチが残る限り使える。 原則
実行されるコードの把握 侵害例 (2025 年 8 月): 仕様変更前の pull_request_target で、修正後も古いブランチに残っていたワークフ ローが悪用され、コード実行と公開トークンの窃取に直結した Nx s1ngularity https://github.com/nrwl/nx/security/advisories/GHSA-cxm3-wv7p-598c 66 -
タグとリリースを書き換えられなくする 利用者はタグを信じて取り込む。 タグを付け替えれば、main ブランチを触らずに全利用者へ汚染版を届けられる。 原則 出所と内容の検証 侵害例 Trivy のサプライチェーン攻撃(2026 年
3 月): trivy-action の 77 タグ中 76 タグが強制更新された https://github.com/aquasecurity/trivy/security/advisories/GHSA-69fq-xp46-6x23 (2025 年 3 月): 全タグが不正コミット 0e58ed8 に付け替えられた tj-actions/changed-files https://www.stepsecurity.io/blog/harden-runner-detection-tj-actions-changed-files-action-is-compromised 系(2026 年 5 月): issues-helper の全タグが付け替えられ、9 月の再有効化後もタグは不正コミットを 指したままだった actions-cool https://thehackernews.com/2026/09/compromised-github-actions-came-back.html 68 -
履歴に残った秘密情報を失効させる が止めるのは新しい push だけで、履歴にある秘密情報は有効なまま残る。 アーカイブ済みや放置されたリポジトリも対象になる。 push protection 原則 盗まれる前提の資格情報 侵害例
(2022 年 4 月): アーカイブ済みの非公開リポジトリにあった機械アカウントのトークンが起点とな り、数十の組織の非公開リポジトリが取得された Heroku / Travis CI https://www.heroku.com/blog/april-2022-incident-review/ 70 -
CI を起動できる主体と条件を限定する と issue_comment は、PR やコメントを送った側の入力を、本家の権限 で動くワークフローに渡す。 pull_request_target 原則 実行されるコードの把握
侵害例 ( 年 月) トークンが盗まれた のワークフローが、フォーク PR のタイトルに注入されたコマンドを実行 Nx s1ngularity 2025 8 : pull_request_target npm https://github.com/nrwl/nx/security/advisories/GHSA-cxm3-wv7p-598c し、 ( 年 月) 研究者が誤字修正の で貢献者になり、以後のフォーク を承認なしに動かした PyTorch 2024 1 : PR PR https://johnstawinski.com/2024/01/11/playing-with-fire-how-we-executed-a-critical-supply-chain-attack-on-pytorch/ ( 年 月) 作者名の末尾が なら無条件に信頼する作りで、攻撃者は自作の App で作っ Claude Code GitHub Action 2026 1 : [bot] Issue https://flatt.tech/research/posts/poisoning-claude-code-one-github-issue-to-break-the-supply-chain/ た から起動できた 72 -
CI 対応 を起動できる主体と条件を限定する の で、フォーク PR の実行承認を「Require approval for all
external 」にする フォーク PR の処理に pull_request_target と issue_comment を使わない pull_request でビルドし、workflow_run で特権処理する二段構成にする workflow_run で受け取る成果物はデータとして扱い、実行しない bot のコメントやラベルをトリガーにしない AI エージェントを起動できる主体は書き込み権限を持つ人に限り、bot は名前の完全一致で判定する Settings Actions contributors 73 -
依存関係を継続的に更新する 対応 の version updates を有効にする リポジトリの .github/dependabot.yml を置く。Settings の
Advanced Security から生成もで きる 組織の設定で有効にできるのは Dependabot alerts と security updates で、version updates はリポジトリごとの dependabot.yml で有効にする Renovate を使う場合は、GitHub App をインストールして renovate.json を置く Dependabot 75 -
自動実行される設定ファイルの変更に所有者の承認を必須にする や .claude/ などを書き換えられる人は、CI の権限と、リポジトリを開く全員の 端末での実行を得る。 通常のレビューでは、これらのパスの変更も所有者以外の承認で main ブランチに入る。 .github/workflows/
原則 出所と内容の検証 侵害例 ( 年 月) 種類の設定ファイルが置かれ、開いた全員の端末でスティーラーが起動した Miasma 2026 6 :4 https://www.stepsecurity.io/blog/miasma-worm-hits-microsoft-again-azure-functions-action-and-72-other-repositoriesdisabled-after-supply-chain-attack-targeting-ai-coding-agents ( 年 月) 追加されたワークフローがシークレットを外部へ送信した GhostAction 2025 9 : https://blog.gitguardian.com/ghostaction-campaign-3-325-secrets-stolen/ の 侵害( 年 月) 侵害されたアカウントで、攻撃者が 月までにワークフローを設定した Salesloft GitHub 2025 3 : 6 https://thehackernews.com/2025/09/github-account-compromise-led-to.html 76 -
自動実行される設定ファイルの変更に所有者の承認を必須にする 対応 で .github/workflows/ などのパスに所有者を置く rulesets の Require review from
Code Owners を有効にする CODEOWNERS 自身と renovate.json と dependabot.yml も対象に含める CODEOWNERS 77 -
バイナリのコミットを禁止する バイナリは差分で中身を読めないので、レビューを通っても内容は確認されていない。 原則 出所と内容の検証 侵害例 (2024 年 3 月): テスト用のバイナリとして
git に置かれたファイルが、バックドアのペイロードだった xz https://www.openwall.com/lists/oss-security/2024/03/29/4 78 -
バイナリのコミットを禁止する 対応 の push rules で、バイナリのパスと拡張子を制限する push rules が使えないリポジトリでは、バイナリの検出を CI
の必須チェックにする rulesets 79 -
コミット署名を必須にする 付与した署名をリポジトリ側で必須にすれば、手元で作った未署名のなりすましコミットは main ブランチに入らない。 原則 出所と内容の検証 侵害例 のサプライチェーン攻撃(2026 年 3
月): メンテナを装った未署名のコミットに v0.69.4 のタグが push され、リ リースワークフローが起動した Trivy https://github.com/aquasecurity/trivy/security/advisories/GHSA-69fq-xp46-6x23 80 -
依存関係の健全性を継続的に監視する 依存先の保守体制とワークフローは、採用した後に変わる。 変化の通知を受ける仕組みがなければ、弱くなった依存先が自分への入口になる。 原則 出所と内容の検証 侵害例 (2018 年 11 月):
保守が止まった依存の引き継ぎ先が攻撃者だった event-stream https://github.com/dominictarr/event-stream/issues/116 (2024 年 3 月): 新しいメンテナが加わり、年単位で権限を広げた xz https://research.swtch.com/xz-timeline 82 -
依存関係の健全性を継続的に監視する 対応 のスコアと個別のチェックを、API と deps.dev で追う Maintained、Branch-Protection、Signed-Releases、Dangerous-Workflow の低下を監視す る Socket
の Install scripts と New author の alert で、インストール時スクリプトの追加や公開元の 変更を受け取る OpenSSF Scorecard 83 -
OpenSSF Scorecard は、リポジトリの保守状況やブランチ保護などの項目を自動で検査し、 各項目を 0〜10 で採点するツールである。 公開 API と deps.dev
でスコアを追え、依存先の健全性の変化を受け取れる。 OpenSSF Scorecard 84 -
Socket Socket は、パッケージの中身を静的に解析し、危険な挙動を alert として知らせるサービスで ある。 依存の追加や更新の PR に GitHub
App がコメントするほか、CLI では socket npm で npm を包んでインストール時に検査する。 alert の例 インストール時に動くスクリプトがある Obfuscated code: 難読化されたコードを含む Known malware: 既知の悪性パッケージである New author: 公開元が変わった Install scripts: 85 -
組織の基本権限を最小にする 対応 組織の基本権限を最小にし、リポジトリごとにロールを付ける オーナーを減らす classic PAT のアクセスを制限し、fine-grained PAT の既定の承認必須を外さない SSO
を必須にして、未認可の PAT と SSH 鍵を使えなくする 87 -
連携 App の権限を最小にする と OAuth App は、連携先にトークンを預ける仕組みである。 連携先が侵害されると、預けたトークンが攻撃者に使われる。 GitHub App
原則 盗まれる前提の資格情報 侵害例 (2022 年 4 月): 連携先が預かっていた OAuth トークンで、npm を含む数十の組織の非公開リポジ Heroku / Travis CI トリが読まれた https://github.blog/news-insights/company-news/security-alert-stolen-oauth-user-tokens/ (2025 年 8 月): Drift の連携 App の OAuth トークンで、多数の組織の Salesforce のデータが読み出 Salesloft Drift された https://cloud.google.com/blog/topics/threat-intelligence/data-theft-salesforce-instances-via-salesloft-drift 88 -
連携 App の権限を最小にする 対応 の利用を承認制にする 連携先の GitHub App は、要求する権限を確認して入れるかを決め、アクセス先を Only
select repositories に限る 後からの権限の追加要求は、承認しない限り付与されない 使わなくなった App は Suspend か Uninstall する bot には機械ユーザーではなく GitHub App を使い、短時間で失効するインストールトークンを渡す 他の SaaS の連携 App も、同じ基準で絞る OAuth App 89 -
bot の承認をマージ要件に数える範囲を限定する 対応 Copilot code review の承認は既定で無効であり、有効にするなら承認を許すファイルパスを指定す る 組織設定の「Allow GitHub
Actions to create and approve pull requests」を無効にする 承認用の GitHub App のトークンで、条件を満たす PR だけを承認するワークフローを置く 作者名が完全一致する パッチ更新である 変更ファイルがロックファイルとマニフェストだけである 必須チェックを通過している 91 -
リポジトリを組織の外へ出せる操作を制限する 可視性の変更、非公開リポジトリのフォーク、リポジトリの移管は、メンバーのトークンが盗 まれたときの持ち出し経路になる。 原則 盗まれる前提の資格情報 侵害例 (2025 年 8 月):
盗んだトークンで非公開リポジトリ 5500 超が公開に切り替えられた Nx s1ngularity https://www.wiz.io/blog/s1ngularity-supply-chain-attack (2025 年 9 月): 非公開リポジトリが -migration の名前で公開された Shai-Hulud https://www.wiz.io/blog/shai-hulud-npm-supply-chain-attack 92 -
隠し文字を lint で検出する 不可視文字と双方向の制御文字は、画面の表示と実際の内容を食い違わせ、人のレビューをす り抜ける。 原則 出所と内容の検証 侵害例 (2025 年
10 月): コミットに不可視文字でコードを埋め込んだ GlassWorm https://www.aikido.dev/blog/glassworm-returns-unicode-attack-github-npm-vscode (2025 年 3 月): 不可視文字で AI エージェントのルールファイルに命令を埋め込んだ Rules File Backdoor https://www.pillar.security/blog/new-vulnerability-in-github-copilot-and-cursor-how-hackers-can-weaponizecode-agents ( 年 月): 双方向の制御文字で、ソースの見た目と意味を変えた Trojan Source 2021 11 https://trojansource.codes/ 94 -
人と bot と App の権限を定期的に棚卸しする 使われなくなったアカウントと連携は、削除しない限り権限を持ったまま増えていく。 持ち主が使っていないので、盗まれて使われても気付かれにくい。 原則 盗まれる前提の資格情報 侵害例
の GitHub 侵害(2025 年 3 月): 侵害されたアカウントで追加されたゲストユーザーが 6 月まで残り、ワーク フローの設定に使われた Salesloft https://thehackernews.com/2025/09/github-account-compromise-led-to.html 98 -
人と bot と App の権限を定期的に棚卸しする 対応 権限の一覧を定期的に確認し、未使用の連携と放置されたアカウントを外す IdP と SCIM(IdP
からのアカウントの自動発行と削除)で、アカウントの発行と削除を連動させる 公開レジストリの maintainer と Trusted Publisher(CI の OIDC による公開)、クラウドのデプロ イロールの信頼ポリシーも対象にする 99 -
監査ログのイベントに通知を付ける 攻撃者は侵害の初期に、コラボレータや App、Deploy key、Webhook を追加して足場を作 る。 これらの操作は、組織の監査ログにイベントとして記録される。 原則 侵害後の手順の事前設計 侵害例
Salesloft になった の GitHub 侵害(2025 年 3 月): 侵害されたアカウントでゲストユーザーが追加され、6 月までの活動の足場 https://thehackernews.com/2025/09/github-account-compromise-led-to.html ( 年 月) セルフホストランナーの登録で永続化した Shai-Hulud 2.0 2025 11 : https://securitylabs.datadoghq.com/articles/shai-hulud-2.0-npm-worm/ 100 -
監査ログのイベントに通知を付ける 対応 監査ログのストリーミングと API を有効にする ストリーミングは Enterprise の設定、API は Enterprise
Cloud の組織で使える どちらもなければ、UI の手動エクスポートか組織 Webhook(member、repository、 workflow_run など)で取り出す 次のイベントも通知の対象にする リポジトリの作成と可視性の変更 セルフホストランナーの登録 ruleset と environment 保護ルールの変更 シークレットの変更と fine-grained PAT のアクセス要求 101 -
リポジトリと連携先の失効手順を持つ リポジトリにはトークン、App、Deploy key、Webhook と連携先が紐づく。 失効に漏れや誤りがあると、攻撃者はアクセスを保つ。 原則 侵害後の手順の事前設計 侵害例 Trivy った
のサプライチェーン攻撃(2026 年 3 月): 2 月の侵害の後に資格情報を一斉に失効させず、攻撃者がアクセスを保 https://github.com/aquasecurity/trivy/security/advisories/GHSA-69fq-xp46-6x23 ( 年 月) 失効させるトークンを誤り、露出したトークンが残って不正な公開に使われた Cline 2026 2 : https://cline.bot/blog/post-mortem-unauthorized-cline-cli-npm 102 -
リポジトリと連携先の失効手順を持つ 対応 、 、 、 、 のシークレット、OIDC の信頼ポリシーの一覧と、失 効の順序を書いておく 失効は一斉に行い、入れ替えの途中の資格情報を残さない
連携先が侵害されたときの一括失効の手順を含める PAT App Deploy key Webhook Actions 103 -
「ビルドする」の範囲 main ブランチへの変更や PR でワークフローが起動し、ランナーの上でコードをビ ルドして成果物ができるまでを扱う。 ランナー main の変更や PR
起動 コード ビルド 成果物 依存関係、Action、シークレット 105 -
のサプライチェーン攻撃 2026 年 3 月 19 日以降、trivy-action をタグで参照していた CI では、次のように進ん
だ。 Trivy 参照 実行 探索 流出 ワークフローの uses: はタグを 指していた。17:43 UTC 以 降、77 タグ中 76 タグが強制 更新され、汚染版のコミットを 指していた 汚染版の entrypoint.sh は、ス キャンの前にスティーラーを実 行した 環境変数と、ランナーのプロセ スのメモリから秘密情報を探し た。sudo で ptrace の制限を 回避した 暗号化して Aqua を装ったタイ ポスクワットのドメインへ送信 した。失敗すると、被害者の GitHub に公開リポジトリを作 って置いた 出典 GitHub アドバイザリ: https://github.com/aquasecurity/trivy/security/advisories/GHSA-69fq-xp46-6x23 Socket: https://socket.dev/blog/trivy-under-attack-again-github-actions-compromise Wiz: https://www.wiz.io/blog/trivy-compromised-teampcp-supply-chain-attack 106 -
「ビルドする」の項目 「ビルドする」でやるべきことは、次の 28 項目である。 重⼤度 ⾼ 重⼤度 中 40 CI
が参照する外部コードをコミット SHA で固定する 53 ランナーを使い捨てにする 41 CI が呼び出せる外部コードを組織の許可リストに限定する 54 依存関係の来歴を検証する 42 取得したスクリプトとバイナリの完全性を検証する 55 ソフトウェア構成分析( SCA)を必須チェックにする 43 CI 上の AI エージェントの権限を絞る 56 CI でロックファイルどおりに解決させる 44 クラウドの資格情報を OIDC で短命に取る 57 シークレットを渡す範囲を使う処理に絞る 45 ⻑期のシークレットを CI から消す 58 ランナーの外向き通信を許可リストに制限する 46 信頼していないコードを動かすジョブにシークレットを渡さない 59 他のジョブから受け取った成果物のダイジェストを照合 47 アーティファクトに秘密情報を含めない 60 git のタグからビルドする 48 コンテナイメージのビルドに秘密情報を残さない 61 来歴を⽣成する 49 CI ジョブのリポジトリへの権限を最⼩にする 62 ランナーの外向き通信を記録する 50 イベントの⼊⼒をコマンドに直接展開しない 63 SBOM を⽣成する 51 キャッシュを信頼していない実⾏と共有しない 64 ランナー上のステップを⾮特権で動かす 52 CI でも依存関係を承認された経路から取る 65 再現可能ビルドにする 66 ワークフローの実⾏記録を保持する 重⼤度 低 67 ログにシークレットを出さない 107 -
CI が参照する外部コードをコミット SHA で固定する が参照し、実行する外部コードの多くは、Git タグで指定される。 タグは可変であり、付け替えられるとコードを変更していないのに汚染版が届く。 CI 原則 出所と内容の検証
侵害例 Trivy た のサプライチェーン攻撃(2026 年 3 月): trivy-action の 77 タグ中 76 タグが汚染版のコミットへ強制更新され https://github.com/aquasecurity/trivy/security/advisories/GHSA-69fq-xp46-6x23 (2025 年 3 月): tj-actions がタグで参照していた reviewdog の Action が先に付け替えら れ、そこから全タグの付け替えに連鎖したと分析されている tj-actions/changed-files https://unit42.paloaltonetworks.com/github-actions-supply-chain-attack/ 108 -
CI が参照する外部コードをコミット SHA で固定する 対応 を完全なコミット SHA で参照し、バージョンをコメントで残す OSS の
pinact で、タグの参照をコミット SHA とバージョンのコメントに変換する dependabot.yml に package-ecosystem: github-actions を置き、SHA とコメントのバージョ ンを更新させる リポジトリの Actions の設定で「Require actions to be pinned to a full-length commit SHA」 を有効にし、固定していない Action を動かさない zizmor の impostor-commit で、参照先が本家に属さないコミットを検出する 依存先のリポジトリは zizmor owner/repo の形で個別に検査する uses: 109 -
zizmor は、GitHub Actions のワークフローと Action の定義を静的に解析し、危険な書き方を 検査するツールである。 リポジトリのパスか owner/repo を渡して実行し、該当箇所を検査項目(audit)の名前と重大
度とともに指摘する。 zizmor 検査項目(audit)の例 参照先のコミットが、そのリポジトリ自体にはない unpinned-uses: uses: の参照がコミット SHA で固定されていない template-injection: テンプレート展開によるコード注入の経路がある dangerous-triggers: pull_request_target のような危険なトリガーを使っている artipacked: git の資格情報がアーティファクトに残りうる impostor-commit: 110 -
CI が呼び出せる外部コードを組織の許可リストに限定する 組織の Actions ポリシーは、配下の全リポジトリが uses: で呼べる Action を制限し、SHA で
の固定を必須にできる。 原則 出所と内容の検証 111 -
CI が呼び出せる外部コードを組織の許可リストに限定する 対応 組織の Actions ポリシーで、GitHub 製と Marketplace の検証済み作者の Action、指定した
Action だけを許可する 「Require actions to be pinned to a full-length commit SHA」を有効にする 汚染が判明した Action は ! 接頭辞でブロックする 112 -
取得したスクリプトとバイナリの完全性を検証する で取得したスクリプトや、ダウンロードした CLI のバイナリを検証せずに実行する と、配布元の改ざんがそのまま CI 内のコード実行になる。 curl | bash
原則 出所と内容の検証 侵害例 (2021 年 4 月): 配布元の Bash Uploader が 2 か月にわたり改ざんされ、CI の環境変数が外部へ送信された Codecov https://about.codecov.io/security-update/ 113 -
取得したスクリプトとバイナリの完全性を検証する 対応 バージョンを固定し、実行前に検証する チェックサムは、公開元のリリースページなど別の経路で得た値と sha256sum -c で照合する 署名は、cosign verify-blob で公開元の鍵か
ID を検証する 固定したバージョンを社内のアーティファクト置き場にミラーし、CI はそこから取る 114 -
( Sigstore keyless 署名) は、長期の署名鍵を持たずに署名する仕組みで、署名者の OIDC の ID に紐づく短命 な証明書で署名し、記録を公開の透明性ログに残す。
検証は鍵ではなく、証明書の ID と発行者が期待どおりかを見る。 Sigstore cosign verify-blob cosign verify-blob trivy_Linux-64bit.tar.gz \ --bundle trivy_Linux-64bit.tar.gz.sigstore.json \ --certificate-identity https://github.com/myorg/tool/.github/workflows/release.yml@refs/tags/v1.4.0 \ --certificate-oidc-issuer https://token.actions.githubusercontent.com GitHub Actions のワークフローの ID と、GitHub の OIDC 発行者で作られた署名だけを受け入れ る 115 -
CI 上の AI エージェントの権限を絞る で動く AI エージェントは、Issue や PR の本文を入力として受け取り、トークンを持ち、外
部と通信する。 この 3 つが揃うと、本文に書かれた命令でトークンが持ち出される。 CI 原則 盗まれる前提の資格情報 侵害例 (2026 年 1 月): Issue 本文の命令で、OIDC トークンを取得するための環境変数を Issue Claude Code GitHub Action に書き戻させた https://flatt.tech/research/posts/poisoning-claude-code-one-github-issue-to-break-the-supply-chain/ (2026 年 2 月): 任意の Issue を Claude に解析させ Bash を許していたため、Issue タイトルの命令で任意のコ ードが実行でき、キャッシュ汚染を経て公開トークンが盗まれた Cline https://cline.bot/blog/post-mortem-unauthorized-cline-cli-npm 116 -
CI 上の AI エージェントの権限を絞る 対応 エージェントに渡すトークンは permissions: で読み取り専用を既定にする 使えるツールを最小にし、シェルの実行を許さない claude-code-action
では allowed_tools でツールを絞る 書き込み先のブランチを制限する 外向き通信の制限では GitHub API 経由の持ち出しを止められないので、トークンの権限で書き込み 先を絞る AI 117 -
クラウドの資格情報を OIDC で短命に取る に置いた長期の鍵は、ランナーで動くすべてのコードから読め、盗まれると失効まで使え る。 OIDC では、クラウドが CI の ID
トークンを検証し、そのジョブにだけ有効な資格情報を発行 する。 CI 原則 盗まれる前提の資格情報 118 -
クラウドの資格情報を OIDC で短命に取る 対応 などへは OIDC フェデレーションにし、ジョブに id-token: write を付けてロールを引き受ける
OIDC トークンの sub にオーナーとリポジトリの数値 ID を含める 名前を取り直したリポジトリによる偽装を防ぐ ID を含む形式が既定になるのは 2026 年 7 月 15 日以降に作成、改名、移管したリポジトリだけ 既存のリポジトリは設定で有効にし、クラウド側の信頼ポリシーも更新する AWS 119 -
長期のシークレットを CI から消す 対応 リポジトリと組織のシークレットを棚卸しし、OIDC に置き換えたものを削除する クロスリポジトリ操作のために残る PAT は、GitHub App
のインストールトークンに替える 残すものには期限と用途を記録し、定期的にローテーションする 121 -
信頼していないコードを動かすジョブにシークレットを渡さない テストやビルドのジョブは、信頼していないコードや依存を動かす。 シークレットを使うジョブと分ければ、シークレットを持たないジョブが侵害されてもシーク レットは読めない。 原則 盗まれる前提の資格情報 侵害例 (2025 年 3
月): ビルドジョブのランナーのメモリから、そのジョブが持っていたシークレッ tj-actions/changed-files トがログに出力された https://www.stepsecurity.io/blog/harden-runner-detection-tj-actions-changed-files-action-is-compromised のサプライチェーン攻撃( 年 月) 汚染された がランナーのメモリからシークレットを抽出した Trivy 2026 3 : Action https://github.com/aquasecurity/trivy/security/advisories/GHSA-69fq-xp46-6x23 122 -
信頼していないコードを動かすジョブにシークレットを渡さない 対応 テストとビルドのジョブでは secrets.* を参照しない 公開とデプロイのシークレットは environment に置き、そのジョブだけが environment: を宣言す
る 再利用ワークフローには secrets: inherit を使わず、必要なものだけを渡す pull_request_target では PR 側のコードを checkout しない actions/checkout の既定の拒否を外さない 更新 bot 用のシークレットは Dependabot secrets のように別に持つ 123 -
アーティファクトに秘密情報を含めない アーティファクトは指定したパスをそのまま保存し、リポジトリの読み取り権限があれば取得 できる。 作業ディレクトリごと渡す構成では、actions/checkout が残す GITHUB_TOKEN や .env も成 果物に入る。
原則 盗まれる前提の資格情報 侵害例 ( 年 月) 大手組織の公開リポジトリで再現され、アーティファクトに .git ディレクトリと が含まれていた ArtiPACKED 2024 8 : GITHUB_TOKEN https://unit42.paloaltonetworks.com/github-repo-artifacts-leak-tokens/ 124 -
アーティファクトに秘密情報を含めない 対応 に persist-credentials: false を指定する アーティファクトに .git や環境ファイルを含めない アップロード前に秘密情報をスキャンする
保持期間を短くする actions/checkout 125 -
コンテナイメージのビルドに秘密情報を残さない や ENV で渡したトークンと、COPY された .env はレイヤーに残る。 pull できる全員が docker
history やレイヤーの展開で読め、公開イメージなら誰でも読める。 ARG 原則 盗まれる前提の資格情報 侵害例 (2021 年 4 月): Docker イメージの作成手順の誤りで抽出された資格情報が、Bash Uploader の改ざんの起 点になった Codecov https://about.codecov.io/security-update/ 126 -
コンテナイメージのビルドに秘密情報を残さない 対応 の secret mount でビルド中だけ秘密情報を渡す docker history --no-trunc や
TruffleHog のイメージスキャンで、レイヤーに秘密情報がないか確認 する BuildKit 127 -
CI ジョブのリポジトリへの権限を最小にする のジョブには、リポジトリを操作するトークンが自動で渡される。 2023 年 2 月より前に作られた組織とリポジトリは、設定を変えていなければ既定が読み書き である。 CI 原則
盗まれる前提の資格情報 侵害例 (2025 年 8 月): 注入されたコマンドが、読み書きできる GITHUB_TOKEN で公開ワークフローを起動 し、npm トークンが盗まれた Nx s1ngularity https://github.com/nrwl/nx/security/advisories/GHSA-cxm3-wv7p-598c ( 年 月) セルフホストランナーで動く別ジョブの を取得し、書き込み権限を得た PyTorch 2024 1 : GITHUB_TOKEN https://johnstawinski.com/2024/01/11/playing-with-fire-how-we-executed-a-critical-supply-chain-attack-onpytorch/ 128 -
イベントの入力をコマンドに直接展開しない のタイトル、ブランチ名、Issue 本文、コミットメッセージは攻撃者が自由に書ける。 これらをテンプレートでシェルのコマンドに直接展開すると、任意のコマンドが実行される。 PR 原則 実行されるコードの把握 侵害例 (2025 年
8 月): PR タイトルが pull_request_target のワークフローでシェルに展開され、公開トーク Nx s1ngularity ンが盗まれた https://github.com/nrwl/nx/security/advisories/GHSA-cxm3-wv7p-598c ( 年 月) ブランチ名の展開からキャッシュ汚染へつながり、汚染版が公開された Ultralytics 2024 12 : https://blog.pypi.org/posts/2024-12-11-ultralytics-attack-analysis/ 130 -
イベントの入力をコマンドに直接展開しない 対応 入力は環境変数に入れてから、シェルで引用符付きの変数として参照する GitHub Actions では ${{ }} を run:
に直接書かない actionlint や zizmor でテンプレートインジェクションを検出し、必須チェックに含める 131 -
キャッシュを信頼していない実行と共有しない キャッシュは、前回の実行が置いたものを無検証で復元する。 信頼していないコードが書いたキャッシュを信頼された実行が復元すると、実行内容が差し替 わる。 原則 出所と内容の検証 侵害例 (2026 年 5
月): フォーク PR が汚染した pnpm ストアのキャッシュを release.yml が復元し、OIDC トーク ンが盗まれて、正規の経路で汚染版が公開された TanStack https://tanstack.com/blog/npm-supply-chain-compromise-postmortem ( 年 月) キャッシュ汚染から公開ワークフローへつながり、汚染版が公開された Ultralytics 2024 12 : https://blog.pypi.org/posts/2024-12-11-ultralytics-attack-analysis/ 132 -
CI でも依存関係を承認された経路から取る 対応 の .npmrc や pip の index を、手元と同じプロキシレジストリに向ける
コンテナは ECR のプルスルーキャッシュを経由させ、上流への直接の pull は外向き通信の制限で塞 ぐ 公開レジストリへの直接アクセスはランナーの外向き通信で止める CI 135 -
ランナーを使い捨てにする ランナーが残ると、ジョブ間で状態が持ち越される。 前のジョブで仕込まれたものが、次のジョブのシークレットを読む。 原則 実行されるコードの把握 侵害例 (2024 年 1 月):
残存するセルフホストランナーにフォーク PR から入り、別ジョブの GITHUB_TOKEN を得た PyTorch https://johnstawinski.com/2024/01/11/playing-with-fire-how-we-executed-a-critical-supply-chain-attack-onpytorch/ 136 -
依存関係の来歴を検証する 来歴(Provenance)には、パッケージを公開したリポジトリとワークフローが署名付きで記録 される。 普段から来歴付きで公開されているパッケージなら、盗んだトークンで外部から公開されたバ ージョンは来歴の欠落で見分けられる。 原則 出所と内容の検証 侵害例 (2024 年
12 月): パイプラインの外から公開された 8.3.45 と 8.3.46 には来歴(attestation)がなく、欠 落で見分けられた Ultralytics https://blog.pypi.org/posts/2024-12-11-ultralytics-attack-analysis/ 138 -
来歴の信頼の連鎖(Trust Chain) 来歴の信頼は、Sigstore のルート CA と GitHub の OIDC 発行者を起点(Trust
Anchor)に、 証明書、署名、来歴、成果物へと連鎖する。 検証は成果物からこの連鎖を逆にたどり、起点に届くことと、証明書の ID が期待どおりである ことを見る。 Trust Anchor 信頼の起点 のルート CA と GitHub の OIDC 発⾏者 Sigstore 証明書 ワークフローの ID を 結び付けた短命な証明書 Rekor に記録 署名 証明書に対応する鍵で 来歴に署名し、Rekor に記録 秘密鍵は署名後に廃棄 来歴 リポジトリ、ワークフロー、 ビルダー、ソースのコミット 成果物 の ダイジェストで結び付く sha256 (信頼の連鎖) Trust Chain 検証は成果物から起点へ逆にたどり、途中の証明書の ID が期待どおりかを⾒る 140 -
依存関係の来歴を検証する 対応 以降は trustPolicy: no-downgrade で、来歴の信頼度が前のバージョンより下がった 依存を失敗させる 信頼度は Trusted Publishing(CI
の OIDC による公開)、来歴あり、なしの順 npm audit signatures で、レジストリの署名と来歴の正しさを検証する ベースイメージは cosign(Sigstore の署名ツール)の verify-attestation で来歴を検証する pnpm 10.21 141 -
ソフトウェア構成分析(SCA)を必須チェックにする 対応 Dependabot alerts と dependency-review-action、または Socket や OSV-Scanner を
CI の必 須チェックにする 新しく追加された依存は、承認するまで失敗させる 143 -
CI でロックファイルどおりに解決させる 対応 や pnpm install --frozen-lockfile を使う pip は
--require-hashes、Terraform は init -lockfile=readonly を使う イメージはダイジェストで pull する npm ci 145 -
シークレットを渡す範囲を使う処理に絞る ジョブ全体の環境変数に置いたシークレットは、そのジョブで動くすべての処理から読める。 使う処理にだけ渡せば、他の処理からは読めない。 原則 盗まれる前提の資格情報 侵害例 (2021 年 4 月):
改ざんされたスクリプトが env の出力を外部へ送信した Codecov https://about.codecov.io/security-update/ 146 -
ランナーの外向き通信を許可リストに制限する ランナーからの通信先を許可リストに限れば、宣言していない宛先へは直接送れなくなる。 依存の取得を終えたステップは全遮断にでき、ビルドの入力も宣言済みのものに限れる。 原則 実行されるコードの把握 侵害例 (2021 年 4 月):
curl で CI の環境変数を外部へ送信した Codecov https://about.codecov.io/security-update/ (2025 年 9 月): curl でシークレットを外部へ送信した GhostAction https://blog.gitguardian.com/ghostaction-campaign-3-325-secrets-stolen/ Trivy のサプライチェーン攻撃(2026 年 3 月): シークレットをタイポスクワットのドメインへ送信した https://www.wiz.io/blog/trivy-compromised-teampcp-supply-chain-attack 148 -
ランナーの外向き通信を許可リストに制限する 対応 StepSecurity の Harden-Runner の egress-policy: block と allowed-endpoints
で許可リストに する 宛先は audit の記録から作る セルフホストでは、ネットワークポリシーで制限する 149 -
Harden-Runner は StepSecurity の GitHub Actions 向けの Action で、ランナーの外向き通 信、ファイルの改変、プロセスを監視し、宛先の許可リストで通信を止める。
Community(無料)は GitHub ホストのランナー上の公開リポジトリだけで、非公開リポジト リとセルフホストランナーは Enterprise(有料)になる。 Harden-Runner 主な設定 で宛先を記録し、block で許可リスト以外の通信を止める(既定は block) allowed-endpoints: block のときに許可する宛先を列挙する disable-sudo-and-containers: ランナーの sudo とコンテナの利用を外す egress-policy: audit 150 -
他のジョブから受け取った成果物のダイジェストを照合する 対応 生成したジョブがダイジェストをジョブの出力に記録し、受け取るジョブはその値と照合する ダイジェストを成果物と同じ場所へ置くと、差し替えと同時に書き換えられる 成果物に attestation を付け、受け取る側で gh attestation verify
で検証する 生成と消費を同一ジョブに限る フォーク PR 由来の成果物は照合の基準も攻撃者が作れるので、コードとして実行せずデータの扱い に留める 152 -
git のタグからビルドする リリース tarball は、git の内容と一致する保証がない。 CI が git のタグから直接ビルドすれば、リリース
tarball にだけある内容は成果物に入らな い。 原則 出所と内容の検証 侵害例 (2024 年 3 月): git にない内容がリリース tarball に混入し、バックドアの起動に使われた xz https://www.openwall.com/lists/oss-security/2024/03/29/4 153 -
git のタグからビルドする 対応 上流のソースを取り込むときは、リリース tarball ではなく git のタグをチェックアウトしてビルドす る 配布する
tarball は CI が Git タグから生成し、手元で作ったものを配布しない 154 -
来歴を生成する 対応 成果物とコンテナイメージに、GitHub の artifact attestations で来歴を付ける コンテナイメージは push-to-registry でレジストリに
attestation を置く 生成を組織の再利用ワークフローに集約し、呼び出し側のジョブからは来歴を偽造できなくする 156 -
( ) SLSA Supply-chain Levels for Software Artifacts は、成果物の作られ方を段階に分けて表す枠組みであり、来歴の有無と偽造の難しさに応 じて
Build レベルが上がる。 来歴の形式(SLSA provenance)もこの枠組みが定義している。 SLSA レベル L1 L2 L3 来歴を作る主体 来歴の偽造に要るもの GitHub Actions では ビルドのステップ(署名なし) ビルドのステップで生成、基盤の ID で署名 基盤が生成と署名 書き換えるだけ ワークフローの書き換え 基盤の脆弱性の悪用 自前のスクリプトで来歴を出す attestation を付ける 組織の再利用ワークフローでビルド 157 -
ランナーの外向き通信を記録する ランナーの外向き通信を記録すれば、侵害の後に何がどこへ送られたかを特定できる。 記録した宛先は、許可リストを作る材料にもなる。 原則 侵害後の手順の事前設計 侵害例 (2025 年 3 月):
StepSecurity のネットワーク異常検知で発見された tj-actions/changed-files https://www.stepsecurity.io/blog/harden-runner-detection-tj-actions-changed-files-action-is-compromised のサプライチェーン攻撃(2026 年 3 月): Aqua を装ったタイポスクワットのドメインへ送信しており、宛先の記 録で検知できた Trivy https://www.wiz.io/blog/trivy-compromised-teampcp-supply-chain-attack 158 -
SBOM 対応 を生成する ( )や docker buildx build --sbom=true で、ビルド時に
SPDX か の を生成する 成果物と同じリリースかレジストリに保存する Syft anchore/sbom-action CycloneDX SBOM 161 -
ランナー上のステップを非特権で動かす ホストのランナーは passwordless sudo が付いており、ステップは root になれる。 root になると、他のプロセスのメモリからシークレットを読める。 GitHub
原則 実行されるコードの把握 侵害例 のサプライチェーン攻撃(2026 年 3 月): ペイロードが sudo で ptrace の制限を回避し、他プロセスのメモリか らシークレットを抽出した Trivy https://socket.dev/blog/trivy-under-attack-again-github-actions-compromise 162 -
ランナー上のステップを非特権で動かす 対応 ホストのランナーでは、Harden-Runner の disable-sudo-and-containers で sudo とコン テナの利用を外す コンテナジョブでは、次の
3 つを守る privileged を使わない capability を落とす Docker ソケットをマウントしない ステップを非 root で動かす セルフホストの Kubernetes ベースのランナーでは、特権 Pod と hostPath を禁止する GitHub 163 -
再現可能ビルドにする 同じソースを独立した環境で再ビルドして成果物と一致すれば、ビルド環境の汚染を検出でき る。 原則 出所と内容の検証 侵害例 (2020 年 12 月):
SUNSPOT(ビルドサーバーに置かれたマルウェア)がビルド中にソースファイルを差し SolarWinds 替えた https://www.crowdstrike.com/en-us/blog/sunspot-malware-technical-analysis/ 164 -
再現可能ビルドにする 対応 ビルドの入力とツールチェーンを固定し、タイムスタンプなどの非決定要素を除く SOURCE_DATE_EPOCH で成果物に埋め込む時刻を固定する Reproducible Builds プロジェクトの文書に非決定要素の一覧と対処法があり、diffoscope は成果物 の差分を可読な形で示す
Nix は入力のハッシュで成果物を識別し、Linux では既定のサンドボックスがネットワークと未宣言 の入力を遮断する Go 1.21 以降のツールチェーンはソースのみを入力とする再現可能ビルドで、-trimpath がビルドパ スを除く 独立した環境で定期的に再ビルドして比較する 165 -
ワークフローの実行記録を保持する 汚染された外部コードを、いつからいつまでどのワークフローが使ったかを答えられなけれ ば、失効の範囲が決まらない。 SHA で固定した Action には Dependabot alerts が出ないので、使った時期は実行記録で調べ
る。 原則 侵害後の手順の事前設計 侵害例 ( 年 月) 影響を受けた期間の実行を、各組織が自分で特定する作業を要した tj-actions/changed-files 2025 3 : https://www.stepsecurity.io/blog/harden-runner-detection-tj-actions-changed-files-action-is-compromised 166 -
ログにシークレットを出さない マスキングは既知のシークレットだけに働き、構造化データに包まれたものはマスクされな い。 公開リポジトリのログは誰でも読める。 原則 盗まれる前提の資格情報 侵害例 (2022 年 6
月): API から取得できたビルドログの標本から、約 7 万 3000 件の資格情報が見つかった Travis CI https://www.aquasec.com/blog/travis-ci-security/ 168 -
のサプライチェーン攻撃 2026 年 3 月、攻撃者は盗んだ公開の権限で、汚染版を次のようにリリースした。 Trivy Trivy の公開 月 19
日 18:22 UTC、2 月の侵害後も残 っていたアクセスで Trivy v0.69.4 が公開 された。3 月 22 日には Docker Hub に v0.69.5 と v0.69.6 の不正イメージが追加 された 3 出典 GitHub LiteLLM の公開 月 24 日 10:39 と 10:52 UTC、CI から 盗まれた PyPI の公開トークンで LiteLLM 1.82.7 と 1.82.8 が公開された 3 取り消し は v0.69.4 を取り下げてアドバイザ リを出し、PyPI は最初の報告から約 3 時間 で LiteLLM の両バージョンを削除した Trivy アドバイザリ: https://github.com/aquasecurity/trivy/security/advisories/GHSA-69fq-xp46-6x23 Trend AI Security: https://www.trendaisecurity.com/en-us/resources-insights/trendai-security-blog/inside-litellm-supply-chain-compromise 172 -
「届ける」の項目 「届ける」でやるべきことは、次の 13 項目である。 重⼤度 ⾼ 68 パッケージの公開に短命な資格情報を使う 69 デプロイのロールを最⼩権限にする
70 本番デプロイのソースを保護ブランチとタグに限定する 71 公開とデプロイの権限を⼈に持たせない 重⼤度 中 72 ⾃組織のスコープと社内パッケージ名を公開レジストリで確 73 デプロイ対象をダイジェストで指定する 74 公開と本番デプロイに⼈の承認を必須にする 75 デプロイ時に来歴を検証する 76 SBOM と来歴を成果物に添えて公開する 77 ⾃分の成果物の公開とデプロイのイベントに通知を付ける 78 緊急時の本番操作を申請制の⼀時的な権限に限定する 79 段階的にロールアウトする 80 汚染された成果物を出してしまったときの⼿順を持つ 173 -
パッケージの公開に短命な資格情報を使う ( 、 )では、レジストリが CI の OIDC トークンを検証し、そのジョブに だけ有効な公開の資格情報を発行する。 既存の公開トークンを失効させれば、盗まれる長期トークンが公開の経路からなくなる。
Trusted Publishing npm PyPI 原則 盗まれる前提の資格情報 侵害例 ( Ultralytics 2024 された 年 12 月): Trusted Publishing に移行した後も失効していなかった API トークンで、8.3.45 と 8.3.46 が公開 https://blog.pypi.org/posts/2024-12-11-ultralytics-attack-analysis/ ( 年 月) から盗まれた の公開トークンで と が公開された LiteLLM 2026 3 : CI PyPI 1.82.7 1.82.8 https://securitylabs.datadoghq.com/articles/litellm-compromised-pypi-teampcp-supply-chain-campaign/ ( 年 月) ワークフローから持ち出された トークンで汚染版が公開された Nx s1ngularity 2025 8 : npm https://github.com/nrwl/nx/security/advisories/GHSA-cxm3-wv7p-598c 174 -
パッケージの公開に短命な資格情報を使う 対応 と PyPI の Trusted Publishing を設定し、公開ワークフローと environment を指定する
既存の公開トークンを失効させる npm 175 -
デプロイのロールを最小権限にする 対応 環境ごとにデプロイのロールを分け、本番環境のロールは本番環境の対象だけを変更できるようにす る コンテナのデプロイでは、イメージの push 先のリポジトリと、更新する対象のサービスに絞る サーバーレスや静的サイトでは、対象の関数やバケットの更新だけを許す Terraform では
plan と apply のロールを分け、plan のロールは読み取りのみにする state の保管先は、この 2 つのロールだけに読ませる 177 -
本番デプロイのソースを保護ブランチとタグに限定する 対応 では environment のデプロイ元ブランチの制限を使い、ワークフローに を書く クラウドの OIDC の信頼ポリシーにも、ブランチと環境の条件を付ける CD
ツールのソース設定で、対象のブランチとタグを固定する GitHub Actions environment: 179 -
公開とデプロイの権限を人に持たせない 端末からの npm publish や terraform apply は、「取り込む」と「ビルドする」の統制をすべ て迂回する。 人のアカウントとロールに公開とデプロイの権限があれば、その資格情報が盗まれた時点でこ
の経路が開く。 原則 盗まれる前提の資格情報 侵害例 ( 年 月) 個人アカウントのトークンで汚染版が手動で公開された Axios 2026 3 : https://www.stepsecurity.io/blog/axios-compromised-on-npm-malicious-versions-drop-remote-access-trojan 180 -
公開とデプロイの権限を人に持たせない 対応 は Publishing access で「Require two-factor authentication and disallow
tokens」を選 び、トークンによる公開を禁止する 2FA 付きの対話的な公開は残るので、maintainer の数を絞る PyPI に同じ設定はなく、既存トークンの失効で代替する クラウド側では、人のロールに本番変更の deny を付ける 社内プロキシレジストリへの書き込み権限も同じ基準で絞る npm 181 -
公開と本番デプロイに人の承認を必須にする マージがデプロイを意味しない経路(手動 dispatch、公開ワークフロー)では、実行の直前に 人の承認を挟む。 承認されるまで、本番用のシークレットをジョブへ渡さないようにする。 原則 出所と内容の検証 侵害例 (2025 年
8 月): 公開用の npm トークンが environment の承認の外にあり、注入されたワークフロー Nx s1ngularity から読めた https://github.com/nrwl/nx/security/advisories/GHSA-cxm3-wv7p-598c ( 年 月) シークレットが の承認の外にあり、追加されたワークフローから読めた GhostAction 2025 9 : environment https://blog.gitguardian.com/ghostaction-campaign-3-325-secrets-stolen/ 186 -
公開と本番デプロイに人の承認を必須にする 対応 では、required reviewers 付きの environment に本番用のシークレットを置く ワークフローには environment: を書く
起動した本人が承認できないよう、Prevent self-review を有効にする 管理者もバイパスできないよう、Allow administrators to bypass configured protection rules を外す 他の CD ツールでも、本番ステージに手動承認のゲートを置く GitHub Actions 187 -
デプロイ時に来歴を検証する 対応 や cosign verify を、デプロイのワークフローに入れる 期待する ID は --owner、--signer-workflow、--source-ref
で指定する Kubernetes では Kyverno や Sigstore の policy-controller で強制する gh attestation verify 189 -
SBOM と来歴を成果物に添えて公開する 対応 リリースに SBOM と attestation を添付する SBOM も
attestation として署名し、成果物のダイジェストに紐づける actions/attest-sbom など npm は Trusted Publishing なら来歴が自動で付き、トークン公開なら --provenance を付ける 自動生成は、公開リポジトリから公開パッケージを出す場合に限る PyPI は pypa/gh-action-pypi-publish が attestation を自動で生成する 191 -
自分の成果物の公開とデプロイのイベントに通知を付ける 盗まれたトークンでの公開に、公開元が最初に気づく手がかりはレジストリの公開イベントで ある。 自分のパイプラインの実行と照合する。 原則 侵害後の手順の事前設計 侵害例 (2024 年 12
月): パイプラインの外から API トークンで 8.3.45 と 8.3.46 が公開された Ultralytics https://blog.pypi.org/posts/2024-12-11-ultralytics-attack-analysis/ (2026 年 3 月): CI から盗まれたトークンで 1.82.7 と 1.82.8 が公開された LiteLLM https://securitylabs.datadoghq.com/articles/litellm-compromised-pypi-teampcp-supply-chain-campaign/ 192 -
自分の成果物の公開とデプロイのイベントに通知を付ける 対応 の公開通知メール、ECR の EventBridge イベント、GHCR の package Webhook、 のデプロイ記録を受け取る
受け取ったイベントを、パイプラインの実行と照合する npm environment 193 -
緊急時の本番操作を申請制の一時的な権限に限定する 対応 の Privileged Identity Management(PIM)は、申請と承認を経て時間制限付 きのロールへ昇格させる AWS の場合は、IAM Identity
Center と連携する AWS Samples のソリューション TEAM (Temporary Elevated Access Management)を使う TEAM は IAM Identity Center の機能ではなく、自分の AWS 環境にデプロイする 操作を記録し、終了後に自動で失効させる Microsoft Entra ID 195 -
段階的にロールアウトする 対応 デプロイは Argo Rollouts や CodeDeploy のカナリアで、指標を見て広げる パッケージは next
などの dist-tag で先に出し、latest へ移すのは確認後にする 197 -
汚染された成果物を出してしまったときの手順を持つ 公開元の対応は「止める」「戻す」「取り下げる」「通知する」の 4 つで、利用者は通知を受ける まで汚染版を使い続ける。 順序を平時に決めておかないと、取り下げと通知が遅れる。 原則 侵害後の手順の事前設計 侵害例 Trivy
のサプライチェーン攻撃(2026 年 3 月): アドバイザリの発行と汚染版の取り下げで対応した https://github.com/aquasecurity/trivy/security/advisories/GHSA-69fq-xp46-6x23 198 -
Trivy の連鎖(再掲) フォークから 細⼯した PR を送る PR のコードが、本家の 権限で実⾏される コードを仕込む
コードを動かす 汚染版の Trivy が LiteLLM の CI に取り込まれる の CI で 汚染版が実⾏される コードを仕込む LiteLLM コードを動かす aqua-bot の PAT 資格情報を盗む PyPI の公開トークン 資格情報を盗む 盗んだ PAT で 汚染版の Trivy を公開 ⽬的を遂⾏する LiteLLM PyPI の汚染版を に公開 ⽬的を遂⾏する 201 -
連鎖で起きたこと 各段で起きたことを、被害者ごとに並べる。 被害者 Trivy Trivy Trivy Trivy LiteLLM LiteLLM LiteLLM
LiteLLM 段階 仕込む 動かす 盗む 遂行 仕込む 動かす 盗む 遂行 起きたこと フォークから細工した PR が送られた PR のコードが本家の権限で実行された bot アカウントの PAT が持ち出された 残存した PAT でリリースワークフローを書き換え、汚染版を公開した 汚染版の Trivy が CI に取り込まれた CI で汚染版が実行された PyPI の公開トークンが持ち出された LiteLLM の汚染版が PyPI に公開された 202 -
連鎖の各段に対応する項目 連鎖の各段に、この資料の項目のどれが対応するかを示す。 被害者 段階 対応する項目 なし Trivy 仕込む 動かす Trivy
盗む Trivy LiteLLM 遂行 仕込む 動かす 盗む LiteLLM 遂行 Trivy LiteLLM LiteLLM を起動できる主体と条件を限定する(防止) 46 信頼していないコードを動かすジョブにシークレットを渡さない(防止)/45 長期のシークレットを CI から消 す(緩和) 23 タグとリリースを書き換えられなくする(防止)/39 リポジトリと連携先の失効手順を持つ(防止) 42 取得したスクリプトとバイナリの完全性を検証する(防止) なし 68 パッケージの公開に短命な資格情報を使う(防止)/58 ランナーの外向き通信を許可リストに制限する(緩和) 39 リポジトリと連携先の失効手順を持つ(防止)/80 汚染された成果物を出してしまったときの手順を持つ(緩 和) 25 CI 203 -
4 つの問い 原則 出所と内容の検証 実行されるコードの把握 盗まれる前提の資格情報 侵害後の手順の事前設計 問い それが本物で、意図したとおりのものだと、何で確かめた そのコードは、誰が動かすと決めた
その資格情報は、盗まれたら何ができる 侵害されたら、最初に何をする 204