信頼できない Pull Request のコードを、書き込み権限やシークレットを持った特権コンテキストで実行してしまう脆弱性パターン。GitHub Security Lab が名付けた。
まず前提:GitHub Actions は「PR が来たら自動でテストを回す」ような自動化ができる。このとき Actions には、リポジトリを操作するための鍵(GITHUB_TOKEN)や API キー等の Secrets が渡されることがある。
何が問題か(たとえ話):
あなたのリポジトリは「自分の家」だと思ってほしい。誰でも改善提案(PR)を送れるように玄関を開けている。ここで危険なのが pull_request_target というトリガー:
- 通常の
pull_requestは「提案者の権限(=ほぼ何も持っていないゲスト)」で動くので安全。 - ところが
pull_request_targetは、他人(fork)から来た PR でも「家主であるあなたの権限(金庫の鍵つき)」でワークフローが走る。 - そのワークフローが、送られてきた PR のコードを取り込んで(
actions/checkout)テストやビルドで実行すると――赤の他人が書いたコードを、あなたの鍵を握ったまま家の中で走らせることになる。
攻撃者は PR のコードにこっそり Secrets を外部に送信する 処理などを仕込む。結果、API キーの窃取・リポジトリの改ざん・パッケージの不正公開などが起きる。
攻撃の流れ(ステップ):
- 攻撃者があなたのリポジトリを fork する。
- fork 側で、テストやビルドのスクリプトに Secrets を盗む処理を仕込んだ PR を送る。
- あなたのリポジトリの
pull_request_targetワークフローが発火。 - このワークフローは base(あなた側)の特権で動く =
GITHUB_TOKEN(write)と Secrets を持っている。 - ワークフローが 攻撃者の PR ブランチを checkout して実行(=他人のコードが特権下で走る)。
- 仕込まれたコードが Secrets を読み取り、攻撃者の外部サーバへ送信。
- 攻撃者は盗んだ鍵で リポジトリ改ざん・パッケージ不正公開などを実行。
攻撃者 あなたのリポジトリ (base)
│ │
① fork して悪意ある PR を作成 ───────────────▶ │
│ │ ② pull_request_target が発火
│ │ ┌──────────────────────────────┐
│ │ │ ワークフロー実行 │
│ │ │ 権限 = base の特権 │
│ │ │ 🔑 GITHUB_TOKEN (write) │
│ │ │ 🔑 Secrets (APIキー等) │
│ │ │ │
│ ③ checkout で「攻撃者のコード」を取り込み実行 ← ここが地雷 │
│ │ │ 悪意あるスクリプトが走る │
│ │ └───────────┬──────────────────┘
│ │ │ ④ Secrets を読む
⑤ 盗んだ鍵で改ざん・不正公開 ◀── 外部へ送信 ──┘ │
│ ▼
▼ 💥 API キー漏洩・乗っ取り
ポイントは 「実行される権限(base の金庫つき)」と「実行されるコード(他人の PR)」がミスマッチしていること。本来この 2 つは揃っているべき(他人のコードなら他人=無権限で動くべき)なのに、pull_request_target はそれをねじれさせてしまう。
- 対策:
- fork PR のコードを実行するなら、権限もシークレットも無い
pull_requestトリガーを使う(ゲスト権限で動かす)。 - どうしても
pull_request_targetが必要なら、PR のコードは checkout・実行しない(ラベル付けなど無害な処理だけに限定)。 - 実行が必要なら 2 段構成にする:まず「鍵なしジョブ」で他人のコードをビルド、その結果を「鍵ありジョブ」がただ反映するだけ、と役割を分ける。
- fork PR のコードを実行するなら、権限もシークレットも無い
「他人の PR を、自分の鍵を持ったまま動かすな」。
pull_request_target× 他人のコード実行 が地雷。