最近、GitHub Actionsは多くのサプライチェーン攻撃で悪用されており、ワークフローの設定ミスが大きな要因となっています。一人で対応するのは危険です!こちらの(チェックリスト)をご確認ください。

なぜGitHub Actionsにはこれほど多くのセキュリティ上の問題があるのでしょうか?
GitHubの組み込みCI/CD 自動化システムであるGitHub Actionsは、セキュリティそのものが脆弱というわけではないが、自滅を招くようなミスを犯してしまう可能性は確かに多い。
このプラットフォームは設計通りに動作しますが、デフォルト設定は概して利便性と柔軟性を重視して設定されており、セキュリティを優先したものではありません。 pull_request_target それには理由があり、変更可能なタグは確かに便利だ。しかし、そうした設計上の判断が攻撃対象領域を生み出し、それが明らかになったのはずっと後のことだった。
GitHub Actionsは、多くのオープンソースプロジェクトにおけるデフォルトCI/CD でもあります。オープンソースプロジェクトを乗っ取られると、ハッカーは最も下流の被害者に侵入することになります。ワークフローには、npmやPyPIへの公開に必要な認証情報が含まれていることが多いため、ワークフローが侵害されると、悪意のあるバージョンのパッケージがプッシュされ、そのパッケージをインストールするすべての開発者も同様に被害を受けることになります。
インシデントにおいて、同じ攻撃ベクトルが繰り返し確認されるもう一つの理由は、攻撃対象領域が長年にわたり公開された研究で詳細に記録されてきたためです。攻撃者は、攻撃の標的を見つけやすくするために、リポジトリをスキャンしてこうした設定ミスを探すこともあります(prt-scanを参照)。GitHubは今後1年間、ユーザーをより確実に保護するためにセキュリティ強化を優先して進めていきますが、GitHubを安全かつ適切に設定するという責任の多くは、依然としてユーザー自身に課せられています。
ベストプラクティスをすべて遵守したからといって、ワークフローが絶対的に安全になるわけではありません。メンテナンス担当者の不正行為やGitHubのインフラにおけるゼロデイ脆弱性から完全に身を守ることはできませんが、最近攻撃者が積極的に悪用している多くの攻撃経路を封じ込めることは可能です。そうすることで、あなたのリポジトリを他の多くのリポジトリよりも攻撃しにくくすることができます。
GitHub Actions ワークフローのセキュリティを維持するためのベストプラクティス
まずはここから始めましょう。このチェックリストの中から5つだけ実行するなら:
- すべてのサードパーティによる操作を完全なコミットSHAに紐付ける
- 既定値に設定
GITHUB_TOKEN読み取り専用権限 - 決して
pull_request_target公開リポジトリで - 決して補間を行わない
${{ github.* }}直接実行:手順 - 長期保存型のシークレットの代わりに、クラウド認証情報にはOIDCを使用してください
ただし、GitHub Actionsに関する安全対策のアドバイスとその必要性を詳しく解説したチェックリストを、ぜひ詳細にご一読いただくことをお勧めします。また、ページ下部に掲載されているツールもご確認ください。これらのベストプラクティスを導入・徹底するのに役立ちます。
トリガーの設定
1. 公開リポジトリでは、pull_request_target を決して使用しないでください
pull_request_target これは、フォークされたプルリクエストによってトリガーされるワークフローが、ベースリポジトリシークレットアクセスして実行できるようにするためのものです。これにより、外部のコントリビューターからのプルリクエストに自動的にラベルを付けたり、コメントを追加したりすることができます。アイデアとしては素晴らしいですが、シークレット アクセスが可能であるため、危険シークレット 。デフォルトでは、ベースリポジトリのデフォルトブランチからワークフローが実行されるため、明示的にチェックアウトしない限り、フォークされたコードは実行されません。 このデフォルトの状態では、トリガー自体は安全です。リスクが生じるのは、フォークされたコードをチェックアウトして組み合わせた場合です。
標準とは異なり プルリクエスト トリガー、 pull_request_target プルリクエスト(PR)の出所にかかわらず、ベースリポジトリのコンテキストで実行されます。誰でもパブリックリポジトリに対してPRを作成できます。そのPRをトリガーとしてワークフローが実行された場合、たとえそのPRがマージされていなくても、ワークフロー内でシークレット 参照されているシークレット すべてランナー環境に読み込まれ、そのランナーで実行されるあらゆるコードからアクセス可能になります。これは「pwnリクエスト」と呼ばれます。攻撃者のスクリプトは、次のような環境変数の参照を行うだけで、それらのシークレットを容易に読み取ることができます。 os.environ.get('MY_SECRET') そして、痕跡を残さずにそれらを攻撃者に送り返す。
プライベートリポジトリでこの機能が必要な場合は、初めて貢献するユーザーからのプルリクエストについて、ワークフローが実行される前にメンテナーの承認を得るよう設定してください。GitHubでは、「設定」>「アクション」>「フォーク・プルリクエストのワークフロー」で、この機能を標準でサポートしています。
2026年6月18日現在、 actions/checkout v7では、デフォルトで一般的なPWNリクエストのパターンをブロックします。 pull_request_target ワークフローでは、明示的に設定しない限り、フォークされたプルリクエストのコードを取得しないようになっています allow-unsafe-pr-checkout: true.
実情:2026年3月のTrivy攻撃は、以下の脆弱性を悪用して行われた pull_request_target. エンジニアたちは、何も実行できないようになっているため安全だと考えていたが、それだけでは不十分だった。PRは「シークレット 」シークレット 送信し、攻撃者はそれを悪用してアカウントを次々と乗っ取った。その直後、ある攻撃者が GitHubのスキャンを開始しました 特に、以下のリポジトリについては pull_request_target 有効化して、約1日で数百件のプルリクエストを開きました。
2. 公開リポジトリでの `workflow_run` の使用は避けてください
workflow_run ワークフローを連鎖させることができ、上流のワークフローが完了すると下流のワークフローがトリガーされます。問題は、上流のワークフローをトリガーした原因(外部のコントリビューターによるフォークのプルリクエストを含む)にかかわらず、下流のワークフローが書き込み権限とシークレットへのアクセス権を持って実行されてしまう点です。
もし上流の プルリクエスト ワークフローはスクリプトインジェクションに対して脆弱であり、攻撃者はプルリクエスト(PR)を介して出力アーティファクトを改ざんすることができます。その後、下流のワークフローは、シークレットへのアクセス権を持つ特権的なコンテキストで、攻撃者が制御するコンテンツを処理します。これにより、信頼できないプルリクエストに含まれる攻撃者が制御するコンテンツが、追加のステップを経由して、シークレットへのアクセス権を持つワークフローに到達することになります。この攻撃経路は、 pull_request_target だが、たどり着く先は同じだ。
最善の対策は、このパターンを避けることです。デプロイがmainブランチへのプッシュ時のみ行われる必要がある場合は、チェーン処理を経由するのではなく、mainブランチへのプッシュによって直接トリガーするようにしてください。 workflow_run. どうしても必要な場合は workflow_run、確認 github.event.workflow_run.event 特権を伴う操作を実行する前に。もし上流のトリガーが プルリクエスト メンテナーからの指示を待つのではなく、何かをデプロイしたりコードを書いたりする前に、一旦手を引いておくべきだ。
ジョブ:
デプロイ:
if: github.event.workflow_run.event == 'push'
Aikido フラグが立つ workflow_run リポジトリ全体で自動検出を行いたい場合は、イベントチェックなしで特権アクションを実行するワークフローを使用してください。
actions/checkout v7では、以下の場所での安全でないfork PRのチェックアウトもブロックされます。 workflow_run 以下のワークフローにおいて workflow_run.event は pull_request* イベント、同じ allow-unsafe-pr-checkout: true オプトアウト。
3. 他の特権トリガーを使用したワークフローの監査
さらに pull_request_target そして workflow_run、シークレットへのアクセス権限を持って実行される他のトリガーにも注意してください。これには以下が含まれます コメントを投稿, 課題, プルリクエストのレビュー、および プルリクエストのレビューコメント. これらはすべて非公開アクセスで実行されるため、外部からの影響を受ける可能性があります。スクリプトの注入に関するルールは同様であり、これらのイベントからの値を直接 実行: 手順。これについては次のセクションで詳しく説明します。
4. フォークのワークフローがデフォルトブランチのキャッシュに書き込まないようにする
以下の操作によってトリガーされるワークフロー pull_request_target そして workflow_run どちらも、デフォルトブランチと共有されているキャッシュへの書き込み権限を持っています。いずれかのイベントをトリガーできるコントリビューターは、そのキャッシュを改ざんし、デフォルトブランチ上で実行されるその後の無関係なワークフローに影響を与えるデータを仕込むことができます。それらのワークフローが何をキャッシュし、何を消費するかを把握し、特権的なクロスフォーク実行から得られたキャッシュデータを、機密性の高いステップの入力として使用しないようにしてください。
信頼できない入力の取り扱い
5. すべてのブランチ名、プルリクエストのタイトル、コミットメッセージ、およびイシューの本文を信頼できない入力として扱うことで、スクリプトの注入を防ぐ
これはSQLインジェクションと同じ原理です。シェルコマンドに含まれるユーザー指定の値は、データではなくコードとして解釈されてしまうため、決して補間を行ってはいけません github.* 値を直接 実行: 手順。解決策は、まずその値を環境変数に割り当て、その後、シェルスクリプト内でその変数を参照することです:
# vulnerable
- run: echo "Branch is ${{ github.head_ref }}"
# safe
- run: echo "Branch is $BRANCH"
env:
BRANCH: ${{ github.head_ref }}
値が環境変数に割り当てられると、シェルはそれを構文解析時に構文として解釈するのではなく、実行時に文字列として読み取ります。これは、ユーザーが制御する入力に由来するあらゆるものに当てはまります: github.head_ref, github.event.pull_request.title, github.event.issue.body, github.event.commits[0].message、および同様のコンテキスト値。優れたSAST としては Aikido のような優れたSASTスキャナーなら、これを検出し、プルリクエストで修正案を提供してくれます。
自然界では: Ultralyticsへの攻撃、ある攻撃者はcurlコマンドを使用してブランチに名前を付け、ワークフローがそのコマンドを直接 実行: ステップを実行し、コードとして実行します。その Nx/s1ngularity攻撃、最初に発見したのは Aikido セキュリティによって最初に発見されたこの情報は、これと組み合わせて pull_request_targetそこで、古いブランチへのプルリクエストが脆弱なワークフローをトリガーし、 GITHUB_TOKEN 読み取り・書き込み権限が付与され、その後、悪意のあるnpmパッケージの公開に悪用された。
6. カスタムワークフロー内のAIエージェントについては、読み取り専用トークンを使用し、生のユーザー入力をプロンプトに含めないようにしてください
GitHub Actions ワークフローで実行される AI エージェントは、他のステップと同様にシークレットへのアクセス権限を持っています。 エージェントがプロンプトの一部としてイシューのタイトル、プルリクエストの説明、またはコミットメッセージを処理する場合、攻撃者はそのテキストに指示を埋め込み、エージェントを操作して、ファイルの変更や、アクセス可能なツールを通じたデータの持ち出しといった特権的なアクションを実行させることが可能です。LLMにおけるプロンプトインジェクションを防ぐ方法はないため、AIエージェントには読み取り以外のアクセス権限を与えないようにし、生のイシューのタイトル、プルリクエストの説明、またはコミットメッセージをプロンプト入力として受け取らせないようにしてください。
自然界では: Aikido 研究者たちはこれを実証した PromptPwnd: Gemini CLIワークフローに悪意のある課題タイトルが渡されたため、エージェントが自身のリポジトリシークレット パブリックな課題スレッドシークレット 書き込んでしまった gh ツールへのアクセス。
7. LLMが生成した出力を、信頼できない入力として扱う
ワークフローがLLMを使用してコマンド、スクリプト、またはファイルパスを生成し、その出力を直接 実行: この手順では、ブランチ名やPRタイトルを補間する場合と同様のインジェクションリスクが生じます。LLMの出力が安全であるとは保証されておらず、プロンプトに影響を及ぼせる攻撃者は、実行される内容にも影響を及ぼす可能性があります。プロンプトインジェクションに関する前の項目で述べたように、LLMの出力をまず環境変数に代入し、可能な限り検証を行い、決してシェルコマンドに直接パイプで渡さないようにしてください。
8. 信頼できないデータを決して書き込まないでください GITHUB_ENV または GITHUB_PATH
宛先 GITHUB_ENV ジョブ内の以降のすべてのステップに対して環境変数を設定します。 GITHUB_PATH 以降のすべての処理において、エントリをシステムのPATHの先頭に追加します。信頼できないコンテンツがこれらのファイルのいずれかに到達した場合、攻撃者は次のような任意の環境変数を設定することが可能になります。 NODE_OPTIONS コードの実行を引き起こす可能性があります。また、PATHの先頭にマルウェアのバイナリを挿入し、信頼できるツールの代わりにそれが呼び出されるようにすることも可能です。この脆弱性が生じるパターンは、アーティファクトをダウンロードするワークフロー、あるいはユーザーが制御する入力を読み取り、それを直接 $GITHUB_ENV サニタイズを行わずに。これらのファイルに書き込まれた内容は、 実行: ステップ。
遺物の取り扱い
9. アーティファクトを、次のような一時ディレクトリに抽出します。 /tmp ワークスペースではなく、ワークフローファイルの上書きを防ぐため
アーティファクトをワークスペースに直接抽出すると、悪意のあるコンテンツを含むアーカイブによって、後続のステップで必要となるワークフローファイル、スクリプト、またはツールが上書きされる可能性があります。抽出先は /tmp あるいは、別の隔離されたディレクトリを使用することで、ワークフローが信頼できるものとみなすあらゆるものから、アーティファクトの内容を隔離することができます。 GitHubではSHA256ダイジェストによる検証もサポートしています より強力な整合性保証が必要な場合は。
10. 機密ファイルを除外する (.env、設定ファイル、認証情報)をアップロードされたアーティファクトから抽出し、 パス: . すべてを飲み込んでしまうようなパターン
会社情報 パス: . ~におけるパターン actions/artifactのアップロード このステップでは、作業ディレクトリ内のすべてのファイルがアップロードされます。これには以下が含まれる場合があります .env ファイル、認証情報が埋め込まれた設定ファイル、または他のステップによってディスクにシークレット キャッシュされたシークレット 。誤って認証情報をインターネット上に公開しないよう、アップロードする内容を明確に指定してください。ワークスペース全体を一括でアップロードするのではなく、特定のディレクトリやファイルタイプを指定し、 .env, *.pem、および同様のファイルを .gitignore およびアーティファクトの除外パターン。
変更可能なアクション参照
11. サードパーティによるすべての操作については、タグやブランチではなく、完全なコミットSHAにピン留めする
タグは略記として便利ですが、その代償として、静的ではないという特徴があります。タグやブランチは変更可能であり、リポジトリの所有者はいつでも別のコミットを指し直すことができます。これは、次のようなタグでは当然のこととされています。 @main. 特定のバージョンを指定する場合は、 uses: some-action@v3, コミットは変わらないと想定されます。しかし、アクションのメンテナーのアカウントが乗っ取られた場合、攻撃者はそのタグを悪意のあるコミットに再設定することができ、下流のすべてのワークフローは、プルリクエストやその他の通知なしに、次回の実行時にそのコミットを取り込んでしまいます。これを防ぐためのベストプラクティスは、代わりにコミットの完全なSHAを固定することです: 使用例:some-action@abc123def456....もちろん、これに対処するのは少々面倒な場合もありますが、Dependabot、Renovate、またはpinactを使用すれば、ピン留めされたSHAを最新の状態に保つことができます。ネイティブのロックファイルはGHAのロードマップに含まれているため、2027年までには利用可能になることを期待しています。
実環境での事例:2025年3月、攻撃者は77個あるバージョンタグのうち76個を aquasecurity/trivy-action 情報窃取型マルウェアを含む悪意のあるコミットに対して。それらのタグ名を参照しているすべてのワークフローが、自動的に悪意のあるコードを取り込んでしまった。
12. 採用前に第三者の行動を精査する
を追加する前に 用途: そのアクションのリポジトリを2分ほど確認してください。作成者がGitHubの認証を受けているか、リポジトリが最後にメンテナンスされたのはいつか、コントリビューターはどれだけいるか、そしてOpenSSFスコアカードのスコアがどうなっているかを確認してください。認証を受けておらず、最近の活動もない単一のメンテナーによる、広く利用されているアクションは、アカウント乗っ取りの格好の標的となります。
13. 推移的依存関係が少ないアクションを優先する
依存関係 が多ければ多いほど、サプライチェーン攻撃に対する脆弱性依存関係 、選択肢依存関係 少ないアクションを選択してください。アクション自体が他のアクションを参照することがあり、そうした推移的な依存関係 実行時に依存関係 。直接的な依存関係に対してSHAピンニングを行っても、その依存関係が自身の依存関係 取り込む場合は、保護されません。
自然界では: tj-actionsの妥協案 このメカニズムを通じて部分的に伝播される。以下に固定された下流のワークフロー tj-actions/changed-files、しかし 変更されたファイル 他動的に参照される reviewdog/action-setup mutableタグによって制御されていたため、reviewdogが侵害された際、下流のすべてのパイプラインで悪意のあるコードが実行されてしまった。
Mutable パッケージの依存関係
14. npm および PyPI パッケージのバージョンを明示的に固定する
浮動小数点型の範囲は、例えば ^1.2.0 または 2.0.0 以上 つまり、ワークフローは実行時に、該当する最新バージョンを自動的にインストールします。パッケージが侵害され、対象範囲内に新しい悪意のあるバージョンが公開された場合、ワークフローは次回の実行時にそれを自動的に取り込みます。特定のバージョンに固定する(1.2.3) そのため、ワークフローでは、ユーザーが明示的に選択したものだけがインストールされます。範囲指定は行わないでください。
実環境での様子: Ultralytics 攻撃は、PyPIに公開された改ざんされたパッケージのバージョンが、依存関係を固定していないワークフローに到達しうることを実証しました。最初の悪意のあるリリースは、検出されるまで数時間にわたり公開されたままであり、その時間は、浮動的な依存関係を取り込んでいるビルドに影響を与えるには十分な長さでした。
15. パッケージマネージャー(pnpm、yarn)が対応している場合は、リリースの最低年齢を設定する
ピン留めされたバージョンであっても、新たに公開された悪意のあるパッケージが、後でアップグレードしようとするまさにそのバージョンに存在している可能性があります。「最小リリース経過時間」の設定を行うことで、パッケージマネージャーに対し、指定された時間(通常は72時間)以内に公開されたパッケージを拒否するよう指示できます。これにより、悪意のあるリリースがビルドに到達する前に、コミュニティがそれを検出して報告する時間を確保できます。pnpmとyarnはこの機能をネイティブでサポートしていますが、npmではまだ対応していません。 Aikido Safe Chain を使用すれば、npm でも同様の対策が可能です(以下を参照)。
16. 可能であれば、証明情報を使用してパッケージの出所を確認する
一部のパッケージレジストリでは、現在「プロヴェナンス認証」に対応しています。これは、公開されたパッケージと、そのパッケージを生成した特定のソースコミットおよびビルドパイプラインとを結びつける暗号化された記録のことです。パッケージをインストールする前にこの認証を確認することで、そのパッケージが主張されているソースからビルドされたものであることを確認できます。npmでは、GitHub Actions経由で公開されたパッケージに対してこの機能をサポートしています。これはまだ比較的新しい取り組みであり、ツールのサポートも完全ではありませんが、お使いのレジストリやパッケージマネージャーが対応している場合は、有効にする価値があります。
シークレット
17.シークレット 参照は環境変数シークレット 行い、コマンドライン引数では決して行わない
コマンドライン引数はプロセス一覧に表示されるため、ランナー上の他のプロセスで /proc それらを読み取ることができます。シークレットを環境変数として渡すことで、プロセス・テーブルに記録されません。ワークフロー内で、シークレットを env: ブロックと参照 $SECRET_NAME シェルコマンド内で、ではなく ${{シークレット.MY_SECRET }} インライン。
実環境では、tj-actionsシークレット ログシークレット 外部へ流出させ(echo/マスキングの問題)、Trivy 攻撃によって PAT が盗み出されました。シークレット 、シークレット アクセスを制限し、万が一問題が発生しても、攻撃者が有効な認証情報を持ち出せないようにすることです。
18. 可能な場合は、リポジトリシークレット 特定の GitHub 環境に限定する
GitHub Environments を使用すると、デプロイ保護シークレット アクセスを制限できるため、次のようなシークレットは PROD_DB_PASSWORD この設定は、本番環境を対象とするワークフローでのみ有効です。この設定を行わない場合、リポジトリ内のすべてのワークフローが、リポジトリレベルのシークレットを読み取ることができるようになります。この設定は、「設定」>「環境」から行えます。
19. ワークフローシークレット 「Scopeシークレット 」は、ジョブレベルではなくステップレベルで設定する
シークレット 、それを必要とするジョブの個々のシークレット 限定して適用することで、最小権限の原則が適用され、アクションが侵害された場合の被害範囲を最小限に抑えることができます。ジョブレベルで宣言されたシークレットは env: そのジョブ内のすべてのステップ(サードパーティのアクションを含む)から、このブロックを読み取ることができます。
野生下では: Shai-Hulud攻撃では、ワークフロースコープを持つトークンが複数の被害者間で再利用されていました。スコープを狭くしていれば、影響範囲を限定できたはずです。
20. クラウドプロバイダー(AWS、Azure、GCP)が対応しているシークレット 有効期間がシークレット 代わりに、OIDC を使用して有効期間が短いクラウド認証情報を取得する
GitHubシークレット として保存された静的なクラウド認証情報は無期限に有効シークレット 、これらが盗まれた場合、被害が広がるリスクが高まります。 OIDC を使用すると、ワークフローから AWS、Azure、または GCP に直接、ジョブに限定された数分間のみ有効な短命トークンをリクエストできるため、攻撃者が盗み出すことのできる認証情報は存在しません。AWS、Azure、GCP はいずれもこれをネイティブにサポートしています。設定には、クラウドプロバイダーと GitHub の OIDC エンドポイント間の信頼関係の構築が必要です。
21. npmの信頼済みパブリッシャーに関するルールを、リポジトリ全体ではなく、特定のワークフローファイルおよび保護されたブランチに限定する
npmの信頼済み公開設定で、ワークフローファイルの正確なファイル名を指定してください(例: release.yml) およびブランチ(例: main) ではなく、リポジトリ全体を信頼するのではなく。これに加え、プルリクエストを必須とし、強制プッシュをブロックするブランチ保護ルールを設定することで、そのパス以外のワークフローからはパブリッシュトークンをリクエストできないようにします。
自然界では: 2026年5月 2026年5月の「Mini Shai-Hulud TanStack」攻撃において、攻撃者は親コミットの履歴を持たない孤立したコミットをTanStack/routerリポジトリにプッシュしました。npmの信頼済みパブリッシャー規則は、保護されたブランチ上の特定のワークフローではなくリポジトリ全体を信頼していたため、このコミットがワークフローをトリガーし、パブリッシュトークンの生成に成功しました。攻撃者はこれを利用して、6分間の間にTanStackエコシステム全体で84個のパッケージの悪意あるバージョンを公開しました。
22. 本番環境を使用するワークフローの実行には、人間の承認を必須とする
GitHub環境を設定し、ワークフローが環境のシークレット アクセスシークレット 環境へデプロイシークレット する前に、必ず誰かによるレビューを必須にするようにします。これは、小規模なチームや、リリース頻度の低いチームにとってより現実的なアプローチです。大規模なチームの場合、これよりもスケーラブルな方法として、有効期限の短い認証情報を使用するOIDCが挙げられます。
23. デバッグ出力であっても、秘密の値を印刷したり出力したりしないようにする
GitHubはログ内の既知のシークレット値をマスキングしますが、これは完全一致の場合に限られます。そのため、シークレットがBase64エンコードされていたり、2つのecho呼び出しに分割されていたりすると、マスキングは機能しません。最も安全な方法は、シークレット しないことです。シークレットが設定されているかを確認する必要がある場合は、値を出力するのではなく、文字列が空でないかを確認してください。
ランナー
24. パブリックリポジトリでは、セルフホスト型のランナーを使用しないでください
誰でもパブリックリポジトリに対してプルリクエスト(PR)を作成できるため、誰でもワークフローの実行を引き起こす可能性があります。GitHubの初回コントリビューター向けのデフォルトの承認設定は、GitHubがホストするランナーにおいてこのリスクを軽減します。GitHubがホストするランナーでは、環境が一時的かつ隔離されているためです。 一方、セルフホスト型ランナーでは、設定ミスや過度に寛容な承認設定があると、同じプルリクエストによってインフラ上でコードが実行されてしまうことになります。GitHubでは、パブリックリポジトリにはGitHubホスト型ランナーを使用し、承認ポリシーを「すべての外部コラボレーターに対して承認を必須にする」ように厳格化することを推奨しています。
実環境での事例:研究者らは PyTorchに対するサプライチェーン攻撃を 。
25. 静的で永続的なランナーの代わりに、一時的なランナーを使用する
静的ランナーはジョブ間で状態を保持するため、侵害されたジョブによって悪意のあるファイル、改変されたバイナリ、または汚染されたキャッシュが残され、そのマシンでのその後の実行に影響を及ぼす可能性があります。一時的なランナーはクリーンな状態で起動し、各ジョブ終了後に破棄されます。Kubernetesベースの環境では「Actions Runner Controller」を使用するか、 --はかない ランナーを手動で登録する際のフラグ。
野生では: Shai-Hulud 侵害されたリポジトリに永続的なセルフホスト型ランナーを登録し、それらを永続的なC2チャネルとして利用した。すべてのトラフィックがgithub.comを経由していたため、ネットワーク監視からは検知されなかった。
26. ランナーのネットワーク送信トラフィックを許可リストに制限する
侵害されたワークフローによる最も危険な行為は、多くの場合、シークレット 攻撃者が制御するシークレット 流出させることです。ワークフローが実際に必要とするドメインのみに外部へのネットワークアクセスを制限することで、これを大幅に困難にすることができます。Harden-Runnerとbullfrogは、いずれもGitHubがホストするランナー上で動作します。セルフホスト型のランナーの場合、ネットワークレベルでのファイアウォール設定によって同様の効果を得ることができます。
GitHub Enterpriseでセルフホスト型ランナーをご利用の場合、トークンのIP許可リストを設定することで、逆方向からの制御が可能になります。これにより、トークンを使用できるIPアドレスが制限されるため、盗まれたトークンを攻撃者のインフラから使用することはできなくなります。
トークンの権限
27. デフォルトを設定する GITHUB_TOKEN 組織またはリポジトリレベルでの読み取り専用権限
会社情報 GITHUB_TOKEN は、ワークフローの実行ごとに自動的に利用可能になります。デフォルトでは、リポジトリ全体に対して広範な読み取りおよび書き込みアクセス権が設定されているため、侵害されたワークフローによってリポジトリへの書き込み、リリースの作成、またはプルリクエストの承認が行われてしまう可能性があります。「設定」>「アクション」>「一般」でデフォルト設定を読み取り専用に設定し、必要な場合のみ明示的に書き込み権限を付与してください。
28. 明示的に宣言する 権限: ワークフローまたはジョブレベルでブロックを設定し、個々のジョブを制限する
組織レベルで読み取り専用をデフォルトに設定すると、その設定が適用されますが、もちろん一部のジョブではそれ以上の権限が必要になる場合があります。ジョブでより高い権限が必要な場合は、 権限: ワークフローレベルではなく、ジョブレベルでブロックします。そうすることで、権限が昇格されたトークンのスコープはそのジョブのみとなり、ワークフロー内の他のすべてのジョブは読み取り専用状態のままになります。
ジョブ:
デプロイ:
権限:
内容: 読み取り
IDトークン: 書き込み実環境では、tj-actions、Trivy、prt-scanといった攻撃はすべて、トークンが必要以上に多くのアクセス権限を持っていたことに起因しています。トークンの権限を厳格化することで、攻撃の影響範囲を全体的に縮小できます。
組織とリポジトリの設定
29. アクションによるプルリクエストの承認機能を無効にする
デフォルトでは、GitHubではワークフローを使用してプルリクエストを承認できるようになっています。 GITHUB_TOKEN. つまり、ワークフローが侵害された場合、レビュープロセスを経ることなく、自身による悪意のある変更を承認してしまう可能性があります。これを無効にするには、[設定] > [アクション] > [一般] > 「GitHub Actionsによるプルリクエストの作成と承認を許可する」で設定を変更してください。(Dependabotによる自動マージのためにこの設定を有効にしているチームもありますが、組織全体でワークフローの承認を有効にするよりも、Dependabot専用のボットアカウントを作成し、そこに明示的なレビュー権限を付与する方が望ましいです。)
30. アクションのソースを、認証済みの作成者または特定のリポジトリに限定する
GitHub のデフォルト設定では、GitHub Marketplace に公開されたすべてのアクションをワークフローで使用できます。 ソースを認証済み作成者または特定の許可リストに限定することで、新たに公開された悪意のあるアクションは、明示的な承認なしにワークフローに採用されることがなくなります。代わりに、開発者はGitHub組織の設定を管理する担当者(通常はプラットフォームチームまたはDevOpsチーム)に承認を依頼し、その担当者が許可リストに追加する必要があります。この設定は、[設定] > [アクション] > [一般] > [アクションと再利用可能なワークフローを許可する] で構成します。
実環境での状況: tj-actionsの侵害 は、チームが取り込むことができるアクションに制限がなかったことも一因となり、23,000のリポジトリに影響を与えました。
31. 組織内で、予期しないセルフホスト型ランナーの登録や、新しく作成されたパブリックリポジトリがないか監視する
トークンが盗まれると、攻撃者は不正なランナーを登録して、永続的なバックドアを仕掛けることができます。また、攻撃者は盗んだ認証情報を公開リポジトリにアップロードすることも常套手段です。ランナーの登録もリポジトリの作成も、チームが直ちに把握すべき事象ですが、GitHubではデフォルトではこれらに対するアラートは送信されません。この問題を回避するには、手動で監視する必要があります。組織の監査ログをSIEMにストリーミングし、以下の条件でアラートを送信するように設定してください。 self_hosted_runners.register イベントとリポジトリの作成。SIEMがない場合は、GitHubAPI を通じて監査ログを取得API 「設定」>「監査ログ」で手動で確認することができます。
実環境での事例:Shai-Hulud攻撃では、侵害されたマシンが 「SHA1HULUD」という名前のセルフホスト型ランナーという名前のセルフホスト型ランナーとして登録され、盗まれた認証情報を使ってデータ流出用のバケットとして機能するパブリックリポジトリが作成されました。これら両方を監視していれば、このキャンペーンを早期に検知できたはずです。
32. CODEOWNERS を使用して、以下の変更に対してセキュリティに配慮したレビューを義務付ける .github/workflows/
ワークフローファイルは、シークレット トークンにアクセスして実行されるコードです。明確な所有権のルールがなければ、リポジトリへの書き込み権限を持つ開発者なら誰でも、セキュリティレビューを経ずにワークフローを変更してマージすることができてしまいます。CODEOWNERSエントリを追加して、 .github/workflows/ セキュリティ上の考慮事項を理解しているレビュアーまたはチームに割り当て、マージ前にCODEOWNERSの承認を必要とするブランチ保護ルールと組み合わせます。
33. 制限または無効化 pull_request_target 必要がない場合は、org またはリポジトリレベルで
GitHub のワークフロー実行保護機能により、管理者はリポジトリや組織全体で、特定のイベントがワークフローをトリガーすることをブロックできます。もし、管理対象のリポジトリのいずれにも pull_request_target、イベントを完全に削除する方が、個々のワークフロー作成者が安全に利用することを期待するよりも良い方法です。この設定は、リポジトリまたは組織の「ワークフロー実行の保護」設定で行います。この機能が必要なリポジトリについては、同じ設定で、どのアクターがイベントをトリガーできるかを制限することも可能です。
GitHub Actionsのワークフローを保護するには Aikido
Aikido 不安定なGitHub Actionsワークフローを検出し、悪用される前に開発者が修正できるよう支援します。
次のような問題を検出します:
- 不適切な使用
pull_request_target - 信頼できないソースを介したスクリプトの注入
github.*入力 - AIを活用したワークフローにおけるテンプレートおよびプロンプトの注入
- ピン留めされていないサードパーティのアクション
- 特権的すぎる
GITHUB_TOKEN権限 - ワークフローにおけるリスクの高い秘密情報の取り扱い
Aikido また、次のことも可能です:
- 修正プルリクエストを自動的に作成する
- リポジトリ全体で安全でないワークフローのパターンを検出する
- 完全なコミットSHAに固定すべき変更可能なGitHub Actionのリファレンスにフラグを立てる
「Aikido Chain」は、以下の方法でパッケージの設置を保護します:
- 既知の悪意のあるnpmおよびPyPIパッケージのブロック
- パッケージの最低年齢制限ポリシーの適用
例えば、 Aikido は、 実行: 手順を説明し、より安全な環境変数のパターンを自動的に提案します。
GitHub Actionsのワークフローを保護する準備が整いました
GitHub Actions ワークフローのセキュリティ対策を行う際は、このチェックリストを手元に置いておいてください。数分で完了できる項目は早めに設定し、チームメンバーと共有して、全員が変更内容に理解を深められるようにしてください。
よくある質問:GitHub Actionsのセキュリティ
GitHub Actionsのワークフローが悪用される最も一般的な方法は何ですか?
スクリプトインジェクションは最も頻繁に見られる攻撃手法です。攻撃者は、ブランチ名、プルリクエストのタイトル、またはイシュー本文に悪意のあるコードを埋め込み、それらの値を直接 実行: これらのステップはシェルコマンドとして実行されます。アクションをコミットSHAに紐付け、インライン補間ではなく環境変数を使用することで、この問題の大部分は解決されます。
とは pull_request_target なぜ危険なのですか?
pull_request_target これは、トリガーとなるプルリクエストがフォークから送信された場合でも、ベースリポジトリシークレットアクセスして実行されるワークフロートリガーです。パブリックリポジトリに対しては誰でもプルリクエストを作成できるため、このトリガーを使用するワークフローでは、外部のシークレット 公開されてしまいます。パブリックリポジトリでは、このトリガーの使用を完全に避けてください。
「アクションをコミットSHAにピン留めする」とはどういう意味ですか?また、なぜそれが重要なのでしょうか?
ほとんどのワークフローでは、サードパーティのアクションをタグで参照します。例えば、 uses: some-action@v3タグは変更可能なため、アクションのメンテナンス担当者のアカウントが乗っ取られた場合、攻撃者はそのタグを悪意のあるコードへと密かに書き換えてしまう可能性があります。コミットの完全なSHAへのピン留めのように uses: some-action@abc123... つまり、ワークフローでは、あなたが確認した内容のみが確実に実行されるということです。
パブリックリポジトリでセルフホスト型ランナーを使うべきでしょうか?
いいえ。誰でもパブリックリポジトリに対してプルリクエスト(PR)を作成し、ワークフローをトリガーすることができます。GitHubがホストするランナーであれば、環境が一時的かつ隔離されているため、管理は可能です。しかし、セルフホスト型のランナーでは、承認ポリシーの設定ミスがあると、外部のコントリビューターがあなたのインフラ上で直接コードを実行できてしまうことになります。
OIDCとは何ですか?また、クラウドの認証シークレット保存するよりも優れている点はどこですか?
シークレット 保存された静的認証 シークレット 無期限にシークレット 、一度盗まれたシークレットは、侵害発生後もしばらくの間危険な状態が続きます。OIDCを利用すれば、ワークフローからAWS、Azure、またはGCPに対して、その特定のジョブに限定された有効期間が数分間の短命トークンをリクエストできます。盗まれる可能性のある長期有効な認証情報は存在しません。
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "TechArticle",
"@id": "https://www.aikido.dev/blog/checklist-github-actions#article",
"headline": "The complete GitHub Actions security checklist",
"description": "GitHub Actions misconfigurations have been behind some of the biggest supply chain attacks of 2025 and 2026. This checklist covers the real attack vectors, what went wrong, and how to fix it.",
"url": "https://www.aikido.dev/blog/checklist-github-actions",
"datePublished": "2026-05-11",
"dateModified": "2026-05-11",
"inLanguage": "en-US",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://www.aikido.dev/blog/checklist-github-actions"
},
"author": {
"@type": "Person",
"@id": "https://www.aikido.dev/team-members/dania-durnas",
"name": "Dania Durnas",
"jobTitle": "Content Marketing",
"url": "https://www.aikido.dev/team-members/dania-durnas",
"worksFor": {
"@type": "Organization",
"name": "Aikido Security",
"url": "https://www.aikido.dev"
},
"sameAs": [
"https://www.linkedin.com/in/daniadurnas/"
]
},
"publisher": {
"@type": "Organization",
"name": "Aikido Security",
"url": "https://www.aikido.dev",
"logo": {
"@type": "ImageObject",
"url": "https://www.aikido.dev/logo.png"
}
},
"keywords": [
"GitHub Actions security",
"CI/CD security",
"supply chain attack",
"pull_request_target",
"script injection",
"mutable action references",
"tj-actions",
"workflow security",
"GitHub Actions checklist",
"DevSecOps",
"secrets management",
"self-hosted runners",
"OIDC",
"GITHUB_TOKEN",
"prt-scan",
"Trivy attack",
"Ultralytics attack",
"Safe Chain"
],
"about": [
{
"@type": "Thing",
"name": "GitHub Actions",
"url": "https://github.com/features/actions"
},
{
"@type": "Thing",
"name": "Supply Chain Security"
},
{
"@type": "Thing",
"name": "CI/CD Pipeline Security"
}
],
"mentions": [
{"@type": "SoftwareApplication", "name": "GitHub Actions"},
{"@type": "SoftwareApplication", "name": "Safe Chain", "url": "https://aikido.dev/safe-chain"},
{"@type": "SoftwareApplication", "name": "Aikido Security", "url": "https://www.aikido.dev"},
{"@type": "Thing", "name": "tj-actions supply chain attack"},
{"@type": "Thing", "name": "Trivy attack"},
{"@type": "Thing", "name": "Ultralytics attack"},
{"@type": "Thing", "name": "prt-scan campaign"},
{"@type": "Thing", "name": "CVE-2025-30066"}
],
"speakable": {
"@type": "SpeakableSpecification",
"cssSelector": ["h1", "h2", ".intro"]
},
"articleSection": [
"Trigger configuration",
"Handling untrusted input",
"Artifact handling",
"Mutable action references",
"Mutable package dependencies",
"Secrets handling",
"Runners",
"Token permissions",
"Org and repo settings"
],
"timeRequired": "PT15M"
},
{
"@type": "BreadcrumbList",
"@id": "https://www.aikido.dev/blog/checklist-github-actions#breadcrumb",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://www.aikido.dev"
},
{
"@type": "ListItem",
"position": 2,
"name": "Blog",
"item": "https://www.aikido.dev/blog"
},
{
"@type": "ListItem",
"position": 3,
"name": "The complete GitHub Actions security checklist",
"item": "https://www.aikido.dev/blog/checklist-github-actions"
}
]
},
{
"@type": "Organization",
"@id": "https://www.aikido.dev#organization",
"name": "Aikido Security",
"url": "https://www.aikido.dev",
"logo": {
"@type": "ImageObject",
"url": "https://www.aikido.dev/logo.png"
}
}
]
}
</script>

