Upgrade to Pro — share decks privately, control downloads, hide ads and more …

開発ワークフローのセキュリティについて考える

Avatar for Takuya Ishizawa Takuya Ishizawa
October 01, 2026
200

 開発ワークフローのセキュリティについて考える

Avatar for Takuya Ishizawa

Takuya Ishizawa

October 01, 2026

Transcript

  1. この講演を作った動機 やパッケージレジストリを経由する侵害が続いている。 個々の対応策は公開されているが、開発ワークフロー全体を通してまとめた資料が少ない。 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
  2. この講演で渡すもの やるべきことを 80 項目に集めた。 開発者の作業順の分類と、全体に通底する原則を添える。 80 の項目 やるべきことの一覧。各項目に概 要と対応を付け、後から自分の環 境と照らして点検できる形にす

    る。 4 つのフェーズ 書く、取り込む、ビルドする、届 ける。開発者の作業の順に並べ、 各項目の置き場にする。 4 つの原則 フェーズをまたいで繰り返し現れ る考え方。各項目に、どの原則の 実装かを付記する。 4
  3. 前提 この講演は次のことを前提とする。 作るソフトウェアそのもののセキュリティは扱わない。 内容は特定の CI ツールや実行環境に依らない。 ただし、説明のために具体的な製品名を使う。 例示の CI ツールは

    GitHub Actions とする。 レジストリは npm、PyPI、Docker Hub、クラウドは AWS を例にする。 対応の実装例として OSS や製品を紹介することがある。 5
  4. のサプライチェーン攻撃 Trivy のサプライチェーン攻撃(2026 年 3 月)では、Trivy への 4 段階の遂行が LiteLLM

    への仕込みになった。 Trivy フォークから 細⼯した PR を送る PR のコードが、本家の 権限で実⾏される コードを仕込む コードを動かす 汚染版の Trivy が LiteLLM の CI に取り込まれる の CI で 汚染版が実⾏される コードを仕込む LiteLLM コードを動かす aqua-bot の PAT 資格情報を盗む PyPI の公開トークン 資格情報を盗む 盗んだ PAT で 汚染版の Trivy を公開 ⽬的を遂⾏する LiteLLM PyPI の汚染版を に公開 ⽬的を遂⾏する 9
  5. つの原則 通底する原則は、次の 4 つである。 4 原則 1 2 3 4

    出所と内容の検証 実行されるコードの把握 盗まれる前提の資格情報 侵害後の手順の事前設計 内容 依存関係、コードの変更、成果物を、受け入れる前に出所と内容 で確かめる 何が実行されるかを把握し、動かすものを自分で決める 短命、最小範囲、実行主体ごとに作る 被害範囲、検知、失効と復旧の順序を事前に決める 10
  6. 経路と原則の対応 4 つの原則は、攻撃者の 4 段階にそれぞれ対応する。 コードを仕込む コードを動かす 資格情報を盗む ⽬的を遂⾏する 原則

    1 原則 2 原則 3 原則 4 出所と内容の検証 実⾏される コードの把握 盗まれる前提の 資格情報 侵害後の⼿順の 事前設計 11
  7. つのフェーズ 開発者の作業を 4 つのフェーズに分け、フェーズごとにやるべきことを列挙する。 4 章 1 2 3 4

    フェーズ 書く 取り込む ビルドする 届ける 範囲 リポジトリをクローンしてから、変更を push するまで 変更がリポジトリに届いてから、main ブランチにマージされるまで ワークフローが起動してから、成果物ができるまで 成果物ができてから、リリースするまで 12
  8. 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
  9. 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
  10. 「書く」の項目 「書く」でやるべきことは、次の 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
  11. インストール時に走るスクリプトを止める の 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
  12. インストール時に走るスクリプトを止める 対応 以降は、依存のインストール時スクリプトが既定で走らない 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
  13. 公開直後のバージョンを採用しない猶予期間を置く 汚染版は、公開から数時間で取り下げられることが多い。 猶予期間の間に取り下げられた汚染版は、インストールの候補に入らない。 原則 出所と内容の検証 侵害例 (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
  14. 公開直後のバージョンを採用しない猶予期間を置く 対応 以降は .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
  15. 社内パッケージの取得先をレジストリの設定で固定する 対応 は .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
  16. 依存関係の解決結果をロックファイルで固定する 対応 ロックファイル(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
  17. リポジトリを 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
  18. リポジトリを IDE で開いたときの自動実行を止める 対応 は Workspace Trust を有効にし、信頼していないリポジトリは制限モードで開く AI エージェントのフォルダを信頼するかの確認を無効にしない

    信頼はリポジトリ単位で永続するので、.claude/ などの設定の差分は pull のたびに見る 組織では Claude Code の managed settings(管理者が配布し、利用者が上書きできない設定)に allowManagedHooksOnly: true を置く Claude Code を対話なしで実行するときは --bare か --settings '{"disableAllHooks": true}' でフ ックを止める VS Code 27
  19. AI エージェントの承認確認を無効にしない 攻撃者は、AI エージェントが読むリポジトリの中身や Web ページに命令を書き込める。 承認なしモードでは、入力に書かれた命令も、マルウェアが起動した AI エージェントの操作 も、人の確認なしに実行される。

    原則 実行されるコードの把握 侵害例 (2025 年 8 月): マルウェアが承認なしのフラグで Claude Code、Gemini CLI、Amazon Q を起動 し、端末の秘密情報を探索させた Nx s1ngularity https://www.wiz.io/blog/s1ngularity-supply-chain-attack 28
  20. AI エージェントの承認確認を無効にしない 対応 承認なしで動かすのは、端末から隔離した devcontainer などの専用環境に限る 管理者が配布し、利用者が上書きできない設定で、承認なしモードを無効にする Claude Code は

    permissions.disableBypassPermissionsMode を "disable" にする MDM の managed-settings.json で配る。Team と Enterprise なら claude.ai コンソールか らも配れる Gemini CLI はシステム設定ファイルで security.disableYoloMode を有効にする 29
  21. 本人のアカウントをフィッシング耐性のある MFA で守る 開発者本人の GitHub、npm、クラウドのアカウントが乗っ取られると、全フェーズの権限が そのまま攻撃者に渡る。 TOTP(認証アプリのワンタイムコード)は、偽サイトが中継すればそのまま使われる。 原則 盗まれる前提の資格情報 侵害例

    (2025 年 9 月): npmjs.help のドメインから 2FA の更新を求めるメールを送り、偽サイトで認証情報を 入力させてメンテナのアカウントを乗っ取った chalk / debug https://www.aikido.dev/blog/npm-debug-and-chalk-packages-compromised 30
  22. 本人のアカウントをフィッシング耐性のある MFA で守る 対応 と npm でパスキーかセキュリティキーを登録し、ログインにはそれを使う GitHub では SMS

    を 2FA から外す GitHub はパスキーだけの 2FA にできないので、TOTP は残したままパスキーを主に使う 組織の設定でメンバーの 2FA を必須にし、Only allow secure two-factor methods で SMS を無効 にする GitHub 31
  23. 長期の資格情報を端末に置かない ~/.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
  24. 長期の資格情報を端末に置かない 対応 は 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
  25. IDE 拡張を許可した発行元のものに限定する 対応 組織では、VS Code のポリシーで許可リストと自動更新の停止を配る AllowedExtensions ポリシーで extensions.allowed を配り、発行元か拡張

    ID の許可リストに する 一覧にない拡張はインストールできず、後から一覧を外れた拡張は無効になる ExtensionsAutoUpdate ポリシーで extensions.autoUpdate を無効にする 個人では、拡張を棚卸しして数を減らし、発行元を確認する extensions.autoUpdate を false にし、更新は内容を確認して手動で入れる 35
  26. 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
  27. MCP サーバーを許可した発行元のものに限定する 対応 組織では、Claude Code の managed settings で MCP

    サーバーの許可リストを配る allowedMcpServers と allowManagedMcpServersOnly: true を組にして、利用者が自分の設 定で広げられなくする deniedMcpServers で既知の不正なサーバーを止める 配布は MDM のほか、claude.ai の管理コンソールからもできる 個人では、発行元を確認したサーバーだけを設定し、リモートのサーバーは接続前に確認する ツール定義のハッシュを記録し、更新での差分を検知する AI エージェントのスキルとプラグインも同じ対象にする 39
  28. コミットに署名する なりすましコミットは、他人の名前とメールを入れるだけで作れる。 署名があれば、本人のコミットと区別できる。 原則 出所と内容の検証 侵害例 のサプライチェーン攻撃(2026 年 3 月):

    メンテナの名前と日時を写したなりすましコミットが作られ、trivyaction のタグがそこへ向けられた Trivy https://snyk.io/articles/trivy-github-actions-supply-chain-compromise/ 43
  29. 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
  30. 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
  31. AI エージェントの外向き通信を許可リストに制限する 対応 サンドボックスで外向き通信を許可リストにする devcontainer は iptables で許可した宛先以外を遮断する srt は

    allowedDomains 以外を既定で拒否する Claude Code は sandbox.network.allowedDomains と strictAllowlist: true で未列挙の宛先 を遮断する 48
  32. 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
  33. AI エージェントに専用の ID を使う 対応 エージェントには本人のトークンを渡さず、専用の fine-grained PAT を期限とリポジトリと権限 を絞って発行する

    トークンは AI エージェントに渡さず、プロキシの MCP サーバーに持たせる プロキシは専用 ID のトークンで GitHub に接続し、AI エージェントに公開するツールを絞る プロキシは AI エージェントとは別のユーザー、コンテナ、ホストのいずれかで動かし、HTTP で公 開する FastMCP の create_proxy で作れる。上流の GitHub MCP サーバーへ専用 ID のトークンで接続 し、HTTP で公開する AI 50
  34. ログインセッションを短命にする を通過した後のセッションも資格情報であり、盗まれれば再認証なしに使われる。 有効期間が長いほど、盗まれたセッションが使える時間も長い。 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
  35. 端末上の資格情報の一覧と失効手順を持つ 端末には、クラウド、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
  36. 端末上の資格情報の一覧と失効手順を持つ 対応 、 、 、 、 、 、 ごとに、失効の手順と を書いておく

    失効の順序を決めておく 端末をネットワークから切り離し、常駐プロセスを除去する 失効と再発行は侵害された端末では行わず、信頼できる別の端末から各サービスの管理画面で行う ~/.aws ~/.npmrc ~/.config/gh ~/.ssh ~/.docker ~/.kube .env URL 54
  37. のサプライチェーン攻撃 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
  38. 「取り込む」の項目 「取り込む」でやるべきことは、次の 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
  39. 依存関係の更新 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
  40. 依存関係の更新 bot に猶予期間を置く 対応 は renovate.json に minimumReleaseAge: "3 days"

    を置く 脆弱性修正の PR(vulnerabilityAlerts、GitHub のみ)は既定で猶予期間の対象外になる Dependabot は dependabot.yml の cooldown に default-days を置く cooldown は security updates には適用されず、脆弱性の修正は自動で例外になる Renovate 60
  41. Dependabot は GitHub に組み込まれた依存関係の更新 bot で、dependabot.yml に書いた 対象を定期的に調べ、新しいバージョンへの PR を作る。

    cooldown は、公開から指定した日数が経ったバージョンだけを候補にする設定である。 Dependabot 61
  42. 秘密情報の push をリポジトリ側で拒否する 対応 と push protection を有効にする 組織の設定で全リポジトリに一括で有効にする 非公開リポジトリでは

    GitHub Secret Protection のライセンスが要る delegated bypass でバイパスできるロールとチームを限定する(Who can bypass push protection for secret scanning を Specific roles or teams にする) 既定では、書き込み権限を持つ全員がバイパスできる secret scanning 63
  43. 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
  44. main 対応 ブランチへの変更にレビューを必須にする で PR を必須にし、承認を 1 名以上にする 規模に応じて承認者数を増やす rulesets

    「Dismiss stale pull request approvals when new commits are pushed」を有効にする rulesets の Bypass list を空にし、Repository admin も入れない 強制 push とブランチの削除を禁止する rulesets は組織で定義して全リポジトリに継承させる 必須ステータスチェックをマージ要件に含める 65
  45. 古いブランチに残ったワークフローを削除する ワークフローはブランチごとにファイルとして残るので、main ブランチで直しても、古いブラ ンチのファイルはそのブランチを対象にした push や PR で動く。 直したはずの脆弱性は、そのブランチが残る限り使える。 原則

    実行されるコードの把握 侵害例 (2025 年 8 月): 仕様変更前の pull_request_target で、修正後も古いブランチに残っていたワークフ ローが悪用され、コード実行と公開トークンの窃取に直結した Nx s1ngularity https://github.com/nrwl/nx/security/advisories/GHSA-cxm3-wv7p-598c 66
  46. タグとリリースを書き換えられなくする 利用者はタグを信じて取り込む。 タグを付け替えれば、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
  47. 履歴に残った秘密情報を失効させる が止めるのは新しい push だけで、履歴にある秘密情報は有効なまま残る。 アーカイブ済みや放置されたリポジトリも対象になる。 push protection 原則 盗まれる前提の資格情報 侵害例

    (2022 年 4 月): アーカイブ済みの非公開リポジトリにあった機械アカウントのトークンが起点とな り、数十の組織の非公開リポジトリが取得された Heroku / Travis CI https://www.heroku.com/blog/april-2022-incident-review/ 70
  48. 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
  49. 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
  50. 依存関係を継続的に更新する 対応 の version updates を有効にする リポジトリの .github/dependabot.yml を置く。Settings の

    Advanced Security から生成もで きる 組織の設定で有効にできるのは Dependabot alerts と security updates で、version updates はリポジトリごとの dependabot.yml で有効にする Renovate を使う場合は、GitHub App をインストールして renovate.json を置く Dependabot 75
  51. 自動実行される設定ファイルの変更に所有者の承認を必須にする や .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
  52. コミット署名を必須にする 付与した署名をリポジトリ側で必須にすれば、手元で作った未署名のなりすましコミットは main ブランチに入らない。 原則 出所と内容の検証 侵害例 のサプライチェーン攻撃(2026 年 3

    月): メンテナを装った未署名のコミットに v0.69.4 のタグが push され、リ リースワークフローが起動した Trivy https://github.com/aquasecurity/trivy/security/advisories/GHSA-69fq-xp46-6x23 80
  53. 依存関係の健全性を継続的に監視する 依存先の保守体制とワークフローは、採用した後に変わる。 変化の通知を受ける仕組みがなければ、弱くなった依存先が自分への入口になる。 原則 出所と内容の検証 侵害例 (2018 年 11 月):

    保守が止まった依存の引き継ぎ先が攻撃者だった event-stream https://github.com/dominictarr/event-stream/issues/116 (2024 年 3 月): 新しいメンテナが加わり、年単位で権限を広げた xz https://research.swtch.com/xz-timeline 82
  54. 依存関係の健全性を継続的に監視する 対応 のスコアと個別のチェックを、API と deps.dev で追う Maintained、Branch-Protection、Signed-Releases、Dangerous-Workflow の低下を監視す る Socket

    の Install scripts と New author の alert で、インストール時スクリプトの追加や公開元の 変更を受け取る OpenSSF Scorecard 83
  55. Socket Socket は、パッケージの中身を静的に解析し、危険な挙動を alert として知らせるサービスで ある。 依存の追加や更新の PR に GitHub

    App がコメントするほか、CLI では socket npm で npm を包んでインストール時に検査する。 alert の例 インストール時に動くスクリプトがある Obfuscated code: 難読化されたコードを含む Known malware: 既知の悪性パッケージである New author: 公開元が変わった Install scripts: 85
  56. 連携 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
  57. 連携 App の権限を最小にする 対応 の利用を承認制にする 連携先の GitHub App は、要求する権限を確認して入れるかを決め、アクセス先を Only

    select repositories に限る 後からの権限の追加要求は、承認しない限り付与されない 使わなくなった App は Suspend か Uninstall する bot には機械ユーザーではなく GitHub App を使い、短時間で失効するインストールトークンを渡す 他の SaaS の連携 App も、同じ基準で絞る OAuth App 89
  58. bot の承認をマージ要件に数える範囲を限定する 対応 Copilot code review の承認は既定で無効であり、有効にするなら承認を許すファイルパスを指定す る 組織設定の「Allow GitHub

    Actions to create and approve pull requests」を無効にする 承認用の GitHub App のトークンで、条件を満たす PR だけを承認するワークフローを置く 作者名が完全一致する パッチ更新である 変更ファイルがロックファイルとマニフェストだけである 必須チェックを通過している 91
  59. リポジトリを組織の外へ出せる操作を制限する 可視性の変更、非公開リポジトリのフォーク、リポジトリの移管は、メンバーのトークンが盗 まれたときの持ち出し経路になる。 原則 盗まれる前提の資格情報 侵害例 (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
  60. 隠し文字を 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
  61. 人と bot と App の権限を定期的に棚卸しする 使われなくなったアカウントと連携は、削除しない限り権限を持ったまま増えていく。 持ち主が使っていないので、盗まれて使われても気付かれにくい。 原則 盗まれる前提の資格情報 侵害例

    の GitHub 侵害(2025 年 3 月): 侵害されたアカウントで追加されたゲストユーザーが 6 月まで残り、ワーク フローの設定に使われた Salesloft https://thehackernews.com/2025/09/github-account-compromise-led-to.html 98
  62. 人と bot と App の権限を定期的に棚卸しする 対応 権限の一覧を定期的に確認し、未使用の連携と放置されたアカウントを外す IdP と SCIM(IdP

    からのアカウントの自動発行と削除)で、アカウントの発行と削除を連動させる 公開レジストリの maintainer と Trusted Publisher(CI の OIDC による公開)、クラウドのデプロ イロールの信頼ポリシーも対象にする 99
  63. 監査ログのイベントに通知を付ける 攻撃者は侵害の初期に、コラボレータや 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
  64. 監査ログのイベントに通知を付ける 対応 監査ログのストリーミングと API を有効にする ストリーミングは Enterprise の設定、API は Enterprise

    Cloud の組織で使える どちらもなければ、UI の手動エクスポートか組織 Webhook(member、repository、 workflow_run など)で取り出す 次のイベントも通知の対象にする リポジトリの作成と可視性の変更 セルフホストランナーの登録 ruleset と environment 保護ルールの変更 シークレットの変更と fine-grained PAT のアクセス要求 101
  65. リポジトリと連携先の失効手順を持つ リポジトリにはトークン、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
  66. のサプライチェーン攻撃 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
  67. 「ビルドする」の項目 「ビルドする」でやるべきことは、次の 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
  68. 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
  69. 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
  70. 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
  71. CI が呼び出せる外部コードを組織の許可リストに限定する 対応 組織の Actions ポリシーで、GitHub 製と Marketplace の検証済み作者の Action、指定した

    Action だけを許可する 「Require actions to be pinned to a full-length commit SHA」を有効にする 汚染が判明した Action は ! 接頭辞でブロックする 112
  72. 取得したスクリプトとバイナリの完全性を検証する で取得したスクリプトや、ダウンロードした CLI のバイナリを検証せずに実行する と、配布元の改ざんがそのまま CI 内のコード実行になる。 curl | bash

    原則 出所と内容の検証 侵害例 (2021 年 4 月): 配布元の Bash Uploader が 2 か月にわたり改ざんされ、CI の環境変数が外部へ送信された Codecov https://about.codecov.io/security-update/ 113
  73. ( 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
  74. 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
  75. CI 上の AI エージェントの権限を絞る 対応 エージェントに渡すトークンは permissions: で読み取り専用を既定にする 使えるツールを最小にし、シェルの実行を許さない claude-code-action

    では allowed_tools でツールを絞る 書き込み先のブランチを制限する 外向き通信の制限では GitHub API 経由の持ち出しを止められないので、トークンの権限で書き込み 先を絞る AI 117
  76. クラウドの資格情報を OIDC で短命に取る 対応 などへは OIDC フェデレーションにし、ジョブに id-token: write を付けてロールを引き受ける

    OIDC トークンの sub にオーナーとリポジトリの数値 ID を含める 名前を取り直したリポジトリによる偽装を防ぐ ID を含む形式が既定になるのは 2026 年 7 月 15 日以降に作成、改名、移管したリポジトリだけ 既存のリポジトリは設定で有効にし、クラウド側の信頼ポリシーも更新する AWS 119
  77. 信頼していないコードを動かすジョブにシークレットを渡さない テストやビルドのジョブは、信頼していないコードや依存を動かす。 シークレットを使うジョブと分ければ、シークレットを持たないジョブが侵害されてもシーク レットは読めない。 原則 盗まれる前提の資格情報 侵害例 (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
  78. 信頼していないコードを動かすジョブにシークレットを渡さない 対応 テストとビルドのジョブでは secrets.* を参照しない 公開とデプロイのシークレットは environment に置き、そのジョブだけが environment: を宣言す

    る 再利用ワークフローには secrets: inherit を使わず、必要なものだけを渡す pull_request_target では PR 側のコードを checkout しない actions/checkout の既定の拒否を外さない 更新 bot 用のシークレットは Dependabot secrets のように別に持つ 123
  79. アーティファクトに秘密情報を含めない アーティファクトは指定したパスをそのまま保存し、リポジトリの読み取り権限があれば取得 できる。 作業ディレクトリごと渡す構成では、actions/checkout が残す GITHUB_TOKEN や .env も成 果物に入る。

    原則 盗まれる前提の資格情報 侵害例 ( 年 月) 大手組織の公開リポジトリで再現され、アーティファクトに .git ディレクトリと が含まれていた ArtiPACKED 2024 8 : GITHUB_TOKEN https://unit42.paloaltonetworks.com/github-repo-artifacts-leak-tokens/ 124
  80. コンテナイメージのビルドに秘密情報を残さない や ENV で渡したトークンと、COPY された .env はレイヤーに残る。 pull できる全員が docker

    history やレイヤーの展開で読め、公開イメージなら誰でも読める。 ARG 原則 盗まれる前提の資格情報 侵害例 (2021 年 4 月): Docker イメージの作成手順の誤りで抽出された資格情報が、Bash Uploader の改ざんの起 点になった Codecov https://about.codecov.io/security-update/ 126
  81. コンテナイメージのビルドに秘密情報を残さない 対応 の secret mount でビルド中だけ秘密情報を渡す docker history --no-trunc や

    TruffleHog のイメージスキャンで、レイヤーに秘密情報がないか確認 する BuildKit 127
  82. 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
  83. イベントの入力をコマンドに直接展開しない のタイトル、ブランチ名、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
  84. イベントの入力をコマンドに直接展開しない 対応 入力は環境変数に入れてから、シェルで引用符付きの変数として参照する GitHub Actions では ${{ }} を run:

    に直接書かない actionlint や zizmor でテンプレートインジェクションを検出し、必須チェックに含める 131
  85. キャッシュを信頼していない実行と共有しない キャッシュは、前回の実行が置いたものを無検証で復元する。 信頼していないコードが書いたキャッシュを信頼された実行が復元すると、実行内容が差し替 わる。 原則 出所と内容の検証 侵害例 (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
  86. CI でも依存関係を承認された経路から取る 対応 の .npmrc や pip の index を、手元と同じプロキシレジストリに向ける

    コンテナは ECR のプルスルーキャッシュを経由させ、上流への直接の pull は外向き通信の制限で塞 ぐ 公開レジストリへの直接アクセスはランナーの外向き通信で止める CI 135
  87. ランナーを使い捨てにする ランナーが残ると、ジョブ間で状態が持ち越される。 前のジョブで仕込まれたものが、次のジョブのシークレットを読む。 原則 実行されるコードの把握 侵害例 (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
  88. 来歴の信頼の連鎖(Trust Chain) 来歴の信頼は、Sigstore のルート CA と GitHub の OIDC 発行者を起点(Trust

    Anchor)に、 証明書、署名、来歴、成果物へと連鎖する。 検証は成果物からこの連鎖を逆にたどり、起点に届くことと、証明書の ID が期待どおりである ことを見る。 Trust Anchor 信頼の起点 のルート CA と GitHub の OIDC 発⾏者 Sigstore 証明書 ワークフローの ID を 結び付けた短命な証明書 Rekor に記録 署名 証明書に対応する鍵で 来歴に署名し、Rekor に記録 秘密鍵は署名後に廃棄 来歴 リポジトリ、ワークフロー、 ビルダー、ソースのコミット 成果物 の ダイジェストで結び付く sha256 (信頼の連鎖) Trust Chain 検証は成果物から起点へ逆にたどり、途中の証明書の ID が期待どおりかを⾒る 140
  89. 依存関係の来歴を検証する 対応 以降は trustPolicy: no-downgrade で、来歴の信頼度が前のバージョンより下がった 依存を失敗させる 信頼度は Trusted Publishing(CI

    の OIDC による公開)、来歴あり、なしの順 npm audit signatures で、レジストリの署名と来歴の正しさを検証する ベースイメージは cosign(Sigstore の署名ツール)の verify-attestation で来歴を検証する pnpm 10.21 141
  90. ソフトウェア構成分析(SCA)を必須チェックにする 対応 Dependabot alerts と dependency-review-action、または Socket や OSV-Scanner を

    CI の必 須チェックにする 新しく追加された依存は、承認するまで失敗させる 143
  91. CI でロックファイルどおりに解決させる 対応 や pnpm install --frozen-lockfile を使う pip は

    --require-hashes、Terraform は init -lockfile=readonly を使う イメージはダイジェストで pull する npm ci 145
  92. ランナーの外向き通信を許可リストに制限する ランナーからの通信先を許可リストに限れば、宣言していない宛先へは直接送れなくなる。 依存の取得を終えたステップは全遮断にでき、ビルドの入力も宣言済みのものに限れる。 原則 実行されるコードの把握 侵害例 (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
  93. ランナーの外向き通信を許可リストに制限する 対応 StepSecurity の Harden-Runner の egress-policy: block と allowed-endpoints

    で許可リストに する 宛先は audit の記録から作る セルフホストでは、ネットワークポリシーで制限する 149
  94. 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
  95. git のタグからビルドする リリース tarball は、git の内容と一致する保証がない。 CI が git のタグから直接ビルドすれば、リリース

    tarball にだけある内容は成果物に入らな い。 原則 出所と内容の検証 侵害例 (2024 年 3 月): git にない内容がリリース tarball に混入し、バックドアの起動に使われた xz https://www.openwall.com/lists/oss-security/2024/03/29/4 153
  96. 来歴を生成する 対応 成果物とコンテナイメージに、GitHub の artifact attestations で来歴を付ける コンテナイメージは push-to-registry でレジストリに

    attestation を置く 生成を組織の再利用ワークフローに集約し、呼び出し側のジョブからは来歴を偽造できなくする 156
  97. ( ) SLSA Supply-chain Levels for Software Artifacts は、成果物の作られ方を段階に分けて表す枠組みであり、来歴の有無と偽造の難しさに応 じて

    Build レベルが上がる。 来歴の形式(SLSA provenance)もこの枠組みが定義している。 SLSA レベル L1 L2 L3 来歴を作る主体 来歴の偽造に要るもの GitHub Actions では ビルドのステップ(署名なし) ビルドのステップで生成、基盤の ID で署名 基盤が生成と署名 書き換えるだけ ワークフローの書き換え 基盤の脆弱性の悪用 自前のスクリプトで来歴を出す attestation を付ける 組織の再利用ワークフローでビルド 157
  98. ランナーの外向き通信を記録する ランナーの外向き通信を記録すれば、侵害の後に何がどこへ送られたかを特定できる。 記録した宛先は、許可リストを作る材料にもなる。 原則 侵害後の手順の事前設計 侵害例 (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
  99. SBOM 対応 を生成する ( )や docker buildx build --sbom=true で、ビルド時に

    SPDX か の を生成する 成果物と同じリリースかレジストリに保存する Syft anchore/sbom-action CycloneDX SBOM 161
  100. ランナー上のステップを非特権で動かす ホストのランナーは passwordless sudo が付いており、ステップは root になれる。 root になると、他のプロセスのメモリからシークレットを読める。 GitHub

    原則 実行されるコードの把握 侵害例 のサプライチェーン攻撃(2026 年 3 月): ペイロードが sudo で ptrace の制限を回避し、他プロセスのメモリか らシークレットを抽出した Trivy https://socket.dev/blog/trivy-under-attack-again-github-actions-compromise 162
  101. ランナー上のステップを非特権で動かす 対応 ホストのランナーでは、Harden-Runner の disable-sudo-and-containers で sudo とコン テナの利用を外す コンテナジョブでは、次の

    3 つを守る privileged を使わない capability を落とす Docker ソケットをマウントしない ステップを非 root で動かす セルフホストの Kubernetes ベースのランナーでは、特権 Pod と hostPath を禁止する GitHub 163
  102. 再現可能ビルドにする 同じソースを独立した環境で再ビルドして成果物と一致すれば、ビルド環境の汚染を検出でき る。 原則 出所と内容の検証 侵害例 (2020 年 12 月):

    SUNSPOT(ビルドサーバーに置かれたマルウェア)がビルド中にソースファイルを差し SolarWinds 替えた https://www.crowdstrike.com/en-us/blog/sunspot-malware-technical-analysis/ 164
  103. 再現可能ビルドにする 対応 ビルドの入力とツールチェーンを固定し、タイムスタンプなどの非決定要素を除く SOURCE_DATE_EPOCH で成果物に埋め込む時刻を固定する Reproducible Builds プロジェクトの文書に非決定要素の一覧と対処法があり、diffoscope は成果物 の差分を可読な形で示す

    Nix は入力のハッシュで成果物を識別し、Linux では既定のサンドボックスがネットワークと未宣言 の入力を遮断する Go 1.21 以降のツールチェーンはソースのみを入力とする再現可能ビルドで、-trimpath がビルドパ スを除く 独立した環境で定期的に再ビルドして比較する 165
  104. ワークフローの実行記録を保持する 汚染された外部コードを、いつからいつまでどのワークフローが使ったかを答えられなけれ ば、失効の範囲が決まらない。 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
  105. のサプライチェーン攻撃 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
  106. 「届ける」の項目 「届ける」でやるべきことは、次の 13 項目である。 重⼤度 ⾼ 68 パッケージの公開に短命な資格情報を使う 69 デプロイのロールを最⼩権限にする

    70 本番デプロイのソースを保護ブランチとタグに限定する 71 公開とデプロイの権限を⼈に持たせない 重⼤度 中 72 ⾃組織のスコープと社内パッケージ名を公開レジストリで確 73 デプロイ対象をダイジェストで指定する 74 公開と本番デプロイに⼈の承認を必須にする 75 デプロイ時に来歴を検証する 76 SBOM と来歴を成果物に添えて公開する 77 ⾃分の成果物の公開とデプロイのイベントに通知を付ける 78 緊急時の本番操作を申請制の⼀時的な権限に限定する 79 段階的にロールアウトする 80 汚染された成果物を出してしまったときの⼿順を持つ 173
  107. パッケージの公開に短命な資格情報を使う ( 、 )では、レジストリが 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
  108. 公開とデプロイの権限を人に持たせない 端末からの npm publish や terraform apply は、「取り込む」と「ビルドする」の統制をすべ て迂回する。 人のアカウントとロールに公開とデプロイの権限があれば、その資格情報が盗まれた時点でこ

    の経路が開く。 原則 盗まれる前提の資格情報 侵害例 ( 年 月) 個人アカウントのトークンで汚染版が手動で公開された Axios 2026 3 : https://www.stepsecurity.io/blog/axios-compromised-on-npm-malicious-versions-drop-remote-access-trojan 180
  109. 公開とデプロイの権限を人に持たせない 対応 は Publishing access で「Require two-factor authentication and disallow

    tokens」を選 び、トークンによる公開を禁止する 2FA 付きの対話的な公開は残るので、maintainer の数を絞る PyPI に同じ設定はなく、既存トークンの失効で代替する クラウド側では、人のロールに本番変更の deny を付ける 社内プロキシレジストリへの書き込み権限も同じ基準で絞る npm 181
  110. 公開と本番デプロイに人の承認を必須にする マージがデプロイを意味しない経路(手動 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
  111. 公開と本番デプロイに人の承認を必須にする 対応 では、required reviewers 付きの environment に本番用のシークレットを置く ワークフローには environment: を書く

    起動した本人が承認できないよう、Prevent self-review を有効にする 管理者もバイパスできないよう、Allow administrators to bypass configured protection rules を外す 他の CD ツールでも、本番ステージに手動承認のゲートを置く GitHub Actions 187
  112. デプロイ時に来歴を検証する 対応 や cosign verify を、デプロイのワークフローに入れる 期待する ID は --owner、--signer-workflow、--source-ref

    で指定する Kubernetes では Kyverno や Sigstore の policy-controller で強制する gh attestation verify 189
  113. SBOM と来歴を成果物に添えて公開する 対応 リリースに SBOM と attestation を添付する SBOM も

    attestation として署名し、成果物のダイジェストに紐づける actions/attest-sbom など npm は Trusted Publishing なら来歴が自動で付き、トークン公開なら --provenance を付ける 自動生成は、公開リポジトリから公開パッケージを出す場合に限る PyPI は pypa/gh-action-pypi-publish が attestation を自動で生成する 191
  114. 自分の成果物の公開とデプロイのイベントに通知を付ける 盗まれたトークンでの公開に、公開元が最初に気づく手がかりはレジストリの公開イベントで ある。 自分のパイプラインの実行と照合する。 原則 侵害後の手順の事前設計 侵害例 (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
  115. 緊急時の本番操作を申請制の一時的な権限に限定する 対応 の Privileged Identity Management(PIM)は、申請と承認を経て時間制限付 きのロールへ昇格させる AWS の場合は、IAM Identity

    Center と連携する AWS Samples のソリューション TEAM (Temporary Elevated Access Management)を使う TEAM は IAM Identity Center の機能ではなく、自分の AWS 環境にデプロイする 操作を記録し、終了後に自動で失効させる Microsoft Entra ID 195
  116. Trivy の連鎖(再掲) フォークから 細⼯した PR を送る PR のコードが、本家の 権限で実⾏される コードを仕込む

    コードを動かす 汚染版の Trivy が LiteLLM の CI に取り込まれる の CI で 汚染版が実⾏される コードを仕込む LiteLLM コードを動かす aqua-bot の PAT 資格情報を盗む PyPI の公開トークン 資格情報を盗む 盗んだ PAT で 汚染版の Trivy を公開 ⽬的を遂⾏する LiteLLM PyPI の汚染版を に公開 ⽬的を遂⾏する 201
  117. 連鎖で起きたこと 各段で起きたことを、被害者ごとに並べる。 被害者 Trivy Trivy Trivy Trivy LiteLLM LiteLLM LiteLLM

    LiteLLM 段階 仕込む 動かす 盗む 遂行 仕込む 動かす 盗む 遂行 起きたこと フォークから細工した PR が送られた PR のコードが本家の権限で実行された bot アカウントの PAT が持ち出された 残存した PAT でリリースワークフローを書き換え、汚染版を公開した 汚染版の Trivy が CI に取り込まれた CI で汚染版が実行された PyPI の公開トークンが持ち出された LiteLLM の汚染版が PyPI に公開された 202
  118. 連鎖の各段に対応する項目 連鎖の各段に、この資料の項目のどれが対応するかを示す。 被害者 段階 対応する項目 なし Trivy 仕込む 動かす Trivy

    盗む Trivy LiteLLM 遂行 仕込む 動かす 盗む LiteLLM 遂行 Trivy LiteLLM LiteLLM を起動できる主体と条件を限定する(防止) 46 信頼していないコードを動かすジョブにシークレットを渡さない(防止)/45 長期のシークレットを CI から消 す(緩和) 23 タグとリリースを書き換えられなくする(防止)/39 リポジトリと連携先の失効手順を持つ(防止) 42 取得したスクリプトとバイナリの完全性を検証する(防止) なし 68 パッケージの公開に短命な資格情報を使う(防止)/58 ランナーの外向き通信を許可リストに制限する(緩和) 39 リポジトリと連携先の失効手順を持つ(防止)/80 汚染された成果物を出してしまったときの手順を持つ(緩 和) 25 CI 203