説明
IssueやPRのタイトル・本文、コメント、コミットメッセージ、作成者情報は、外部ユーザーが制御できる場合があります。${{ }}式でこれらをrunのコマンドへ直接埋め込むと、シェルの実行前にコードへ置換され、コマンドインジェクションにつながる可能性があります。式を引用符で囲むだけでは不十分です。
想定される影響
- 注入されたコマンドが、実行環境のファイルやジョブに渡されたトークン・シークレットへアクセスする可能性があります。
- その権限によっては、成果物の改ざんやリポジトリ操作の悪用につながります。
対処方法
- 外部の値をインラインのシェルコードへ直接埋め込まないでください。必要な値はステップの
envで渡し、シェルでは"$VALUE"のように引用した変数として扱ってください。evalなどで再びコードとして評価しないでください。 - 想定する形式を検証し、コマンドの引数を分けてください。
GITHUB_TOKENとシークレットへのアクセスも必要な範囲に限定してください。 pull_request_targetなど権限の強いワークフローでは、信頼できないPRのコードをチェックアウトしたり実行したりしないでください。
例
最初の例はPR本文をコマンドへ埋め込みます。二つ目は固定されたリポジトリ内のテストコマンドを実行する別の例で、信頼できるベースブランチのコードと必要なテストスクリプトがあることを前提とします。
変更前
yaml
name: Pull Request Workflow
on:
pull_request_target:
types:
- opened
jobs:
process_pull_request:
runs-on: ubuntu-latest
steps:
- name: Echo Pull Request Body
run: |
echo "Pull Request Body: ${{ github.event.pull_request.body }}"
PR本文が実行するシェルコードの一部になります。攻撃者が制御できる本文を二重引用符で囲んでも、コード注入の危険は残ります。
変更後
yaml
name: check-go-coverage
on:
pull_request_target:
branches: [master]
jobs:
coverage:
name: Check Go coverage
runs-on: ubuntu-latest
steps:
- name: Checkout Source
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go 1.22.x
uses: actions/setup-go@v5
with:
go-version: 1.22.x
- name: Run test metrics script
id: testcov
run: |
make test-coverage-report | tee test-results
echo "coverage=$(cat test-results | grep "Total coverage: " test-results | cut -d ":" -f 2 | bc)" >> $GITHUB_ENV
これらのコマンドはPR本文を直接埋め込みません。後から外部の値を追加する場合もデータとして渡し、強い権限で信頼できないコードを実行しないでください。