説明
actions/github-scriptのscriptはJavaScript関数の本体として実行されます。Issueのタイトルなど外部の値を${{ }}で直接埋め込むと、コードの生成時に文字列の範囲を抜け出し、別のコードを実行される可能性があります。ファイルパスに使う場合は、パスの範囲も別途制限する必要があります。
想定される影響
- 注入されたコードが実行環境のファイルを読み取ったり、成果物を改ざんしたりする可能性があります。
- ジョブのトークンと権限によっては、Issue・コメントなどの操作を悪用されたり、シークレットが漏えいしたりするおそれがあります。
対処方法
- 必要な値は
context.payloadからデータとして読むか、envで渡してprocess.envから読んでください。コード文字列に埋め込んだり、evalで評価したりしないでください。 - ファイルパスやAPI引数の形式と範囲を検証してください。データとして渡しても、その後のすべての使い方が安全になるわけではありません。
- トークンとシークレットへのアクセスを限定し、強い権限のジョブで信頼できないコードを実行しないでください。
例
コメントの作成に必要な権限を明示した例です。最初の例の/tmpファイル読み取りは危険を示すもので、そのファイルが用意されていなければ失敗します。アクションは確認済みのバージョンやコミットに固定してください。
変更前
yaml
name: test-script-run
on:
issues:
types: [opened]
permissions:
contents: read
issues: write
jobs:
script-run:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run script
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const body = fs.readFileSync('/tmp/${{ github.event.issue.title }}.txt', {encoding: 'utf8'});
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'Thanks for reporting!'
})
return true;
IssueのタイトルをJavaScript文字列とファイルパスへ直接埋め込みます。コード注入とパスの操作の両方に対処する必要があります。
変更後
yaml
name: test-script-run
on:
issues:
types: [opened]
permissions:
contents: read
issues: write
jobs:
script-run:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run script
uses: actions/github-script@v7
with:
script: |
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'Thanks for reporting!'
})
return true;
不要なファイル読み取りを削除し、固定のコメントだけを投稿します。タイトルが必要なら、コードに埋め込まずデータとして読み、検証してください。