何を見るチェックか
Scorecard は、ワークフローファイルの中に既知の危険な書き方が無いかを探します。
代表的なのは次の2つです。
1. pull_request_target と、フォーク側のコードの実行を組み合わせる
on: pull_request_target # ← 書き込み権限つきのトークンが渡る
jobs:
build:
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }} # ← 他人のコードを取ってくる
- run: npm install && npm test # ← それを実行する
pull_request_target は、フォークからの Pull Request でも
元リポジトリの権限つきトークンでワークフローを動かします。
そこで他人のコードを取得して実行すると、誰でもその権限を使えることになります。
2. 信頼できない入力をスクリプトに埋め込む(スクリプトインジェクション)
- run: echo "${{ github.event.issue.title }}" # ← Issue のタイトルがそのまま shell に入る
Issue のタイトルやブランチ名は誰でも自由に決められます。
それを run: に直接埋め込むと、任意のコマンドを実行させられます。
見つかると 0 点、見つからなければ 10 点です。中間はありません。
点が低いと何を意味するか
0点は、他の項目の0点とは意味が違います。
多くの Scorecard の項目は「確認できなかった」を示しますが、 この項目の 0 は 「具体的な該当箇所が見つかった」 を意味します。 Scorecard の詳細結果には、ファイル名と行番号まで出ます。
該当した場合、そのリポジトリの CI は、 条件次第で第三者が任意のコードを実行できる状態にあります。 成立すればリポジトリの書き換えやシークレットの取得につながりえます。
ただし、実際に成立するかは権限の設定や実行条件にもよります。 0 だから今まさに悪用されている、という意味ではありません。
誤解しやすい点
「0点だから使えない」と即断しないでください。判断には2つの補足が要ります。
-
これはそのプロジェクトの CI の問題であって、配布されるコードの問題ではありません。 あなたがそのライブラリをインストールして使うこと自体に、 直接この欠陥が持ち込まれるわけではありません。 影響するのは「そのプロジェクトのリリースが汚染されうるか」という経路です。
-
pull_request_targetを使っていること自体は問題ではありません。 フォークからの Pull Request でラベルを付けたりコメントしたりするために、 正当に使われる書き方です。危険になるのは **「権限つきで動く」×「他人のコードを取得して実行する」**が揃ったときだけです。
一方で、10点でも「CI が守られている」証明にはなりません。 Scorecard が見ているのは既知のパターンだけで、 自作スクリプトの中身までは追いません。
なお、この項目は修正が比較的はっきりしているという特徴があります。 0 のプロジェクトを見つけたら、Issue で知らせるとメンテナーの助けになります。
採用する側が確認すべきこと
-
Scorecard の詳細結果で、該当ファイルと行を確認する。 この項目は具体的な位置を出すので、実際のワークフローを開いて読めます。
-
権限と合わせて読む。 → Token-Permissions 権限が読み取りのみに絞られていれば、成立しても被害は限られます。
-
リリース経路を確認する。 リリースが CI から自動で公開されているなら、影響は実配布物まで届きます。 手動でリリースしているなら、経路は1つ挟まります。
-
自分のプロジェクトのワークフローも同じ目で見る。
pull_request_targetを使っている箇所、${{ github.event.* }}をrun:に埋め込んでいる箇所を探してください。 多くのプロジェクトに1つ2つは見つかります。
メンテナーなら何を改善できるか
pull_request_target の場合
フォーク側のコードをチェックアウトしないのが基本です。 ラベル付けやコメントのように、コードを実行しない処理にだけ使います。
フォークのコードをテストしたい場合は、通常の pull_request イベントを使います。
こちらは権限つきトークンが渡らないので、他人のコードを動かしても被害が広がりません。
スクリプトインジェクションの場合
${{ }} を run: に直接埋め込まず、環境変数を経由させます。
# 前
- run: echo "${{ github.event.issue.title }}"
# 後
- env:
TITLE: ${{ github.event.issue.title }}
run: echo "$TITLE"
環境変数に入れれば、値がシェルの構文として解釈されません。
あわせて
- ワークフローの権限を読み取りのみに絞る → Token-Permissions
- フォークからの Pull Request で走るワークフローに、承認を必須にする
(
Settings → Actions → Require approval for all external contributors)