pull_request_target とキャッシュポイズニングの危険を潰す
フォークからの PR を pull_request_target で扱うワークフローは「書き込み権限+シークレット付きで外部コードを動かす」危険があるため、使い方を限定し、静的解析で検出する。
何を解決するか / 背景
- TanStack の npm 侵害は、
pull_request_targetの強い権限、GitHub Actions のキャッシュポイズニング、ランナーのメモリからの抽出を連鎖させ、最終的に OIDC トークン(npm publish 権限)を得たとポストモーテムで説明されている(@t_wada の紹介)。 - 過去 18 か月の主要な OSS サプライチェーン攻撃は、ほぼ
.github/workflowsの YAML に行き着く。GitHub Actions は「リリース鍵置き場」に近い(@labelmake)。
対策チェックリスト
pull_request_targetでは PR の head を checkout してビルド・実行しない。ラベル付けやコメントなど、コードを実行しない処理に限定する。- 外部コードを扱うなら
pull_request(読み取り権限・シークレットなし)で動かし、結果だけをworkflow_runで受け取る。 - ワークフロー先頭で
permissions: {}→ ジョブごとに最小権限を付与。id-token: writeは publish ジョブだけ。 - リリースジョブは信頼できないジョブとキャッシュを共有しない(キャッシュキーを分ける/リリース時はキャッシュを使わない)。
- publish は Environment(承認者付き)に閉じ込める。
- 静的解析で検出:
ghasec(セキュリティ重視の GitHub Actions 静的解析、@matsuu の紹介)や zizmor / actionlint を CI に入れる。
yaml
on: pull_request_target
permissions: {}
jobs:
label:
permissions: { pull-requests: write }
runs-on: ubuntu-latest
steps:
- run: echo "コードは checkout しない"注意点
${{ github.event.pull_request.title }}などをrun:に直接埋め込むとスクリプトインジェクションになる。環境変数経由で渡す。- AI エージェント(Gemini CLI の GitHub Action など)をワークフローで動かす場合、ヘッドレス環境でワークスペースが自動信頼される不備が報告された。外部入力を読むエージェントには明示的な信頼設定と最小権限を。
出典
- @t6adev · 2026-05-12
- @t_wada · 2026-05-12
- @labelmake · 2026-04-29
- @matsuu · 2026-04-05
- @yousukezan · 2026-04-27 (Gemini CLI GHSA)
- @about_hiroppy · 2026-03-31 (GitHub Actions 侵害の振り返りスライド)