zizmorでGitHub Actionsを静的解析し、公開ワークフローのサプライチェーンリスクを低減する

zizmorでGitHub Actionsを静的解析し、公開ワークフローのサプライチェーンリスクを低減する

TanStack/Routerのnpmサプライチェーン攻撃をきっかけに、Rust製のGitHub Actions静的解析ツール「zizmor」を試してみました。このツールでワークフローがどの程度の指摘を受けるか、また対応方法について紹介します。
2026.05.17

はじめに

2026年5月11日、TanStack/Router の npm パッケージ群が侵害され、@tanstack/* の 42 パッケージ・計 84 バージョンに悪意のあるコードが公開されました。ポストモーテムが非常に参考になります。

https://tanstack.com/blog/npm-supply-chain-compromise-postmortem

GitHub Actionsのworkflowファイルも「攻撃可能なコード」として静的に監査しておくべきだと改めて感じる事案でした。

TanStackによる対応・再発防止策の詳細はインシデント直後のfollow-up postに公開されています。

https://tanstack.com/blog/incident-followup

この中で再発防止策の一つとしてAdding zizmor as a required PR check on every repoと挙げられており、Rust製のGitHub Actions静的解析ツールzizmorの存在を知りました。

https://docs.zizmor.sh/

今回のインシデントを成立させた要因は概ね次の通りです。

  • pull_request_targetトリガでforkのPRコードをチェックアウトしビルドしてしまう(Pwn Request)
  • そのジョブが書き出したGitHub Actionsのキャッシュが、後からmainのrelease workflowにrestoreされる(Cache Poisoning)
  • restoreされた攻撃コードが、release workflowに付与されたid-token: write権限によりジョブ実行中にランナーのメモリ上で発行されるOIDCトークン(GitHubが発行するJWT)をRunner.Workerプロセスのメモリから読み取り、それをnpm trusted publisher連携経由でregistry.npmjs.orgに直接提示することで悪意のあるバージョンをpublish

なお3つ目について、release workflow内に定義された正規のPublish Packagesステップは実行されておらず、test/cleanupフェーズで動いていたマルウェア(cache restore 経由で混入した依存パッケージの postinstall スクリプトとして起動)が自らid-token: write権限を使ってOIDCトークンを発行させ、registry.npmjs.orgに直接POSTした、という点がポストモーテムで明記されています。

Publish is authenticated via OIDC trusted-publisher binding for TanStack/router release.yml@refs/heads/main — but it does not come from the workflow's defined Publish Packages step, which was skipped because tests failed. It comes from the malware running during the test/cleanup phase, which mints an OIDC token via the workflow's id-token: write permission and POSTs directly to registry.npmjs.org

TanStack npm supply-chain compromise postmortem

前述のパターンのうち最初の 2 つには、対応する zizmor の audit ルールが存在します(Pwn Request 系は dangerous-triggers、Cache Poisoning は cache-poisoning)。3 つ目は runtime exploitation のステップなので静的解析の対象外です。

今回はこのzizmorでいくつかのパターンのワークフローがどの程度の指摘を受けるか、その後の修正も含め試してみます。

前提

趣味作っているブログシステムのCI, CDに対して静的解析を行います。

https://github.com/shuntaka9576/shuntaka-dev

zizmorのバージョンは以下を利用します。

$ zizmor --version
zizmor 1.24.1

zizmorのPersona

zizmor は audit ごとに「どの persona で出すか」が決められており、--persona <name> で出力の粒度を切り替えられる。

Persona 用途 出る指摘の傾向
regular(デフォルト) 一般的な開発者向け 誤検出が少なく、対処価値が高い指摘のみ。pedantic / auditor 専用の audit は抑制される
pedantic より厳しい lint 的チェック regular に加えて、慣習・スタイル寄りの指摘(anonymous-definitionconcurrency-limitsundocumented-permissions など)が出る
auditor セキュリティ監査者向け 低 confidence や疑似陽性の可能性があるものも含めて全件出す(pedantic の指摘も含む)

今回の .github では regular で 30 件中 20 件が抑制されていたが、--persona auditor を付けることで全件確認できた。

各 Persona での実行結果

.github 配下に対して 3 つの persona で実行した時のサマリは以下。各 finding の詳細は、後続の「解析結果: ...」セクションでワークフロー単位の --persona auditor 出力を参照してください。(文字数の都合上)

$ zizmor .github
30 findings (20 suppressed, 8 fixable): 0 informational, 0 low, 5 medium, 5 high

$ zizmor --persona pedantic .github
30 findings (1 suppressed, 8 fixable): 6 informational, 9 low, 6 medium, 8 high

$ zizmor --persona auditor .github
30 findings (0 suppressed, 8 fixable): 6 informational, 9 low, 7 medium, 8 high

auditorregular / pedantic で抑制される指摘も全て出すため、本記事の以降の解析は --persona auditor で進める。N suppressed は、内部で検出されたが現在の persona ではコンソールに表示されない件数を指す。

出力の見方

はじめに

zizmor の出力は Rust コンパイラの診断フォーマットに似ています。1 件の finding を例に、構成要素を見ていきます。

warning[artipacked]: credential persistence through GitHub Actions artifacts
  --> .github/workflows/ci.yaml:13:9
   |
13 |         - name: Checkout
   |  _________^
14 | |         uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
   | |________________________________________________________________________________^ does not set persist-credentials: false
   |
   = note: audit confidence Low
   = note: this finding has an auto-fix
   = help: audit documentation https://docs.zizmor.sh/audits/#artipacked

severityラベル

warning[artipacked]: credential persistence through GitHub Actions artifacts

行頭の error / warning / help / info が finding の severity を表します。末尾の集計行 ... informational, ... low, ... medium, ... high と対応します。

ラベル severity 主な意味
error[...] high 確度の高い、優先的に修正すべき問題
warning[...] medium 潜在的に問題があり、対応した方が良い
help[...] low セキュリティ問題というより「ベストプラクティス上やった方が良い」改善提案
info[...] informational 補足情報。--pedantic 以上でのみ出るものが多い

上の例は warning[artipacked] なので severity は medium になります。

audit confidence

   = note: audit confidence Low

severity とは独立した「この検出がどれだけ確度の高い疑いか」を示す軸です。高いほど検出ロジックに迷いが無く、低いほどヒューリスティック寄り(誤検出の可能性が混ざる)になります。

confidence 検出の確度 解釈 対応方針
High ほぼ確実 静的に判定でき、誤検出の余地がほぼ無い そのまま信用して対応してよい
Medium 状況次第 文脈次第で実害が無いケースもある 影響範囲を確認した上で対応
Low ヒューリスティック 検出条件は満たすが実害は文脈依存 個別に精査、ケースによっては抑制(ignore:)も視野

severity と confidence は独立した軸です。実際の finding でも以下のように組み合わせは様々です。

  • 重大度は低いが検出は確実: info[anonymous-definition] (severity = info / confidence = High)
  • 重大度は高いが誤検出もあり得る: warning[artipacked] (severity = medium / confidence = Low)

ドキュメントリンク

   = help: audit documentation https://docs.zizmor.sh/audits/#artipacked

= の後ろに付くこの help: は、severity ラベルの help[...](= low)とは別物で、Rust の = help: と同じく全 finding 共通で出る参照ドキュメントリンクです。同じ "help" は位置で見分けます。

  • 行頭の help[audit-name]: ... → severity ラベル(= low)
  • = help: audit documentation → URL → 参照ドキュメントリンク(severity 問わず常時付く)

auto-fixの有無

   = note: this finding has an auto-fix

この note が付いている finding は zizmor --fix で自動修正できます。後述の各表の「Auto-fix」列はこの note の有無に対応します。

解析結果: CI

サマリ

単体実行: zizmor --persona auditor .github/workflows/ci.yaml — 3 findings (1 fixable)
$ zizmor --persona auditor .github/workflows/ci.yaml
 INFO zizmor: 🌈 zizmor v1.24.1
 INFO audit: zizmor: 🌈 completed .github/workflows/ci.yaml
warning[artipacked]: credential persistence through GitHub Actions artifacts
  --> .github/workflows/ci.yaml:13:9
   |
13 |         - name: Checkout
   |  _________^
14 | |         uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
   | |________________________________________________________________________________^ does not set persist-credentials: false
   |
   = note: audit confidence Low
   = note: this finding has an auto-fix
   = help: audit documentation https://docs.zizmor.sh/audits/#artipacked

info[anonymous-definition]: workflow or action definition without a name
 --> .github/workflows/ci.yaml:9:3
  |
9 |   ci:
  |   ^^ this job
  |
  = note: audit confidence High
  = tip: use 'name: ...' to give this job a name
  = help: audit documentation https://docs.zizmor.sh/audits/#anonymous-definition

help[concurrency-limits]: insufficient job-level concurrency limits
 --> .github/workflows/ci.yaml:3:1
  |
3 | on: [push]
  | ^^^^^^^^^^ workflow is missing concurrency setting
...
9 |   ci:
  |   -- job affected by missing workflow concurrency
  |
  = note: audit confidence High
  = help: audit documentation https://docs.zizmor.sh/audits/#concurrency-limits

3 findings (1 fixable): 1 informational, 1 low, 1 medium, 0 high

https://github.com/shuntaka9576/shuntaka-dev/blob/018f7f4b7af7de390b9e78d368422f1d1b37f88f/.github/workflows/ci.yaml

#[1] severity confidence 該当行 persona Auto-fix 概要 エラーメッセージの内容
1 warning Low L13-L14 regular, pedantic, auditor あり actions/checkoutpersist-credentials: false を設定していないため、GITHUB_TOKEN.git/config に残り artifact 経由で漏れうる warning[artipacked]: credential persistence through GitHub Actions artifacts
does not set persist-credentials: false
2 info High L9 pedantic, auditor なし ci ジョブに name: が設定されていない info[anonymous-definition]: workflow or action definition without a name
this job
3 help High L3 pedantic, auditor なし workflow に concurrency 設定が無く、同一ブランチへの連続 push で並列実行されてしまう help[concurrency-limits]: insufficient job-level concurrency limits
workflow is missing concurrency setting

対応(#1): warning[artipacked]

https://github.com/shuntaka9576/shuntaka-dev/blob/018f7f4b7af7de390b9e78d368422f1d1b37f88f/.github/workflows/ci.yaml#L12-L14

ArtiPACKED 攻撃という手法です。zizmorには、コンソールに出力されている通り、対応するauditのドキュメントがあります。こちらを読んだ上で対応を進めるのが良いでしょう。

ホスティングされたドキュメントのリンクが出力されますが、今回は更新によるリンク切れを防ぐため公開元となるGitHubのマークダウンを利用します。

https://docs.zizmor.sh/audits/

https://github.com/zizmorcore/zizmor/blob/4f70a67a48f4f08c986de63922d181b14c199607/docs/audits.md#L113-L179

zizmorのaudit.mdの通り、v6.0.2を使っていることから severity が warning になっています。

zizmor v1.17.0 以降、@actions/checkout の v6.0.0 以上を使用している場合、この監査で見つかる問題の深刻度が低く設定されるようになりました。

これは、@actions/checkout v6.0.0 において、認証情報の保存場所がより誤用を防ぎやすい場所へと変更されたことを反映したものです。

詳細については、GitHub コミュニティのディスカッション(orgs/community?179107)を参照してください。

https://github.com/zizmorcore/zizmor/blob/4f70a67a48f4f08c986de63922d181b14c199607/docs/audits.md#L134-L141

ArtiPACKED 攻撃詳細はこちらをご覧ください

ArtiPACKED 攻撃の流れ: checkout で .git/config に保存された GITHUB_TOKEN が、ビルド後のアーティファクトアップロード経由で公開され、攻撃者がダウンロードしてリポジトリへ書き戻すまでの 6 ステップ

  1. ワークフローがコードをチェックアウト(トークンが .git/config に保存される)
  2. ビルドプロセスが走る
  3. アーティファクトのアップロードがワークスペース全体(., ./, ${{ github.workspace }} など)を含めてしまう
  4. 攻撃者が GitHub UI からそのアーティファクトをダウンロード
  5. .git/config から GITHUB_TOKEN を抽出
  6. ワークフローの権限の範囲でリポジトリにアクセス

本 finding が confidence = Low なのは、zizmor が見ているのは (1) の persist-credentials: false 未設定だけで、実害には (3) の artifact に .git が含まれること、(4) で攻撃者がアクセス可能であることまで揃う必要があり、そこは静的解析では追えないためです。とはいえ前提条件を潰せば後段に依らず安全側に倒せるので対応する価値はあります。

こちらで対応完了とします。

     steps:
       - name: Checkout
         uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+        with:
+          persist-credentials: false

       - name: Setup node
         uses: ./.github/actions/setup-node

対応(#2): info[anonymous-definition]

job定義のname指定漏れ (severity = info)

https://github.com/shuntaka9576/shuntaka-dev/blob/018f7f4b7af7de390b9e78d368422f1d1b37f88f/.github/workflows/ci.yaml#L8-L9

zizmorの定義は以下

https://github.com/zizmorcore/zizmor/blob/4f70a67a48f4f08c986de63922d181b14c199607/docs/audits.md#L17-L62

severity が info なので危険性はないが、補足情報を見る限り定義した方が良さそうです。このような情報も検出してくれることで、チームで共通認識や記法を揃える指針になるため非常に便利です。

しかし、name: を省略すると、GitHub ActionsのUI上でそのワークフローやアクションが「匿名」として表示されます。その結果、どの定義が実行されているのかを把握しにくくなります。
!!! note "注意"
この項目はセキュリティ上の影響がないため、--pedantic(厳密モード)オプションを指定した場合のみ実行されるチェック項目です。

nameをつけて対応します。

修正後
  jobs:
    ci:
+     name: CI
      runs-on: ubuntu-latest
      steps: ...

対応(#3): help[concurrency-limits]

並列実行制限です

https://github.com/shuntaka9576/shuntaka-dev/blob/018f7f4b7af7de390b9e78d368422f1d1b37f88f/.github/workflows/ci.yaml#L3

zizmorの定義は以下

https://github.com/zizmorcore/zizmor/blob/4f70a67a48f4f08c986de63922d181b14c199607/docs/audits.md#L308-L342

GitHub Actionsのデフォルト設定では、同じワークフローのインスタンスを複数同時に実行できるようになっています。たとえ新しく開始された実行が古いものを完全に上書きするようなケースであっても、並行して処理が行われます。
これは、特に課金対象となるランナーにおいて、攻撃者にリソースを浪費させる隙を与えることになります。またそれとは別に、ワークフロー実行ID(run ID)ではなく、ワークフロー名やジョブ名などの識別子を使ってアーティファクトを特定しようとする際に、予期せぬ競合状態(レースコンディション)を引き起こす原因にもなり得ます。

こちらも上記通り、severity = help ですが、設定が漏れやすく問題が発覚してから入れるケースもある類の内容です。audit ドキュメントに従い、以下のように concurrency: を追加して解消します。

+ concurrency:
+   group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
+   cancel-in-progress: true

修正後対応

全て適用後再度確認し、指摘事項が見つからないことを確認しました。

$ zizmor --persona auditor .github/workflows/ci.yaml
 INFO zizmor: 🌈 zizmor v1.24.1
 INFO audit: zizmor: 🌈 completed .github/workflows/ci.yaml
No findings to report. Good job!

すでに解説済みの指摘も含めて最終的な差分は以下となります。

https://github.com/shuntaka9576/shuntaka-dev/commit/a9b3fe25d6694a68afe42f6a43138a55dd67be23

解析結果: デプロイ

サマリ

単体実行: zizmor --persona auditor .github/workflows/deploy.yaml — 2 findings
$ zizmor --persona auditor .github/workflows/deploy.yaml
 INFO zizmor: 🌈 zizmor v1.24.1
 INFO audit: zizmor: 🌈 completed .github/workflows/deploy.yaml
error[excessive-permissions]: overly broad permissions
  --> .github/workflows/deploy.yaml:20:3
   |
20 |   id-token: write
   |   ^^^^^^^^^^^^^^^ id-token: write is overly broad at the workflow level
   |
   = note: audit confidence High
   = help: audit documentation https://docs.zizmor.sh/audits/#excessive-permissions

help[undocumented-permissions]: permissions without explanatory comments
  --> .github/workflows/deploy.yaml:20:3
   |
20 |   id-token: write
   |   ^^^^^^^^^^^^^^^ needs an explanatory comment
   |
   = note: audit confidence High
   = help: audit documentation https://docs.zizmor.sh/audits/#undocumented-permissions

2 findings: 0 informational, 1 low, 0 medium, 1 high

https://github.com/shuntaka9576/shuntaka-dev/blob/018f7f4b7af7de390b9e78d368422f1d1b37f88f/.github/workflows/deploy.yaml

# severity confidence 該当行 persona Auto-fix 概要 エラーメッセージの内容
1 error High L20 pedantic, auditor なし workflow レベルで id-token: write を付けており、全ジョブが OIDC トークンを発行できてしまう error[excessive-permissions]: overly broad permissions
id-token: write is overly broad at the workflow level
2 help High L20 pedantic, auditor なし permissions: ブロックに何故その権限が必要かの説明コメントが無い help[undocumented-permissions]: permissions without explanatory comments
needs an explanatory comment

対応(#1): error[excessive-permissions]

deploy.yamlreusable-deploy.yaml を呼ぶだけですが、reusable workflow の権限は caller 側の許可範囲が上限となるため、caller の id-token: write 自体は必須です。問題は権限の必要性ではなく、それを workflow レベルに置いている点で、現状は同 workflow 内の全ジョブが OIDC トークンを発行できる過剰なスコープになっています。

https://github.com/shuntaka9576/shuntaka-dev/blob/018f7f4b7af7de390b9e78d368422f1d1b37f88f/.github/workflows/deploy.yaml#L19-L21

zizmorの定義は以下

https://github.com/zizmorcore/zizmor/blob/4f70a67a48f4f08c986de63922d181b14c199607/docs/audits.md#L589-L702

一般的に permissions はできるだけ最小に、利用箇所のできるだけ近くで宣言すべきです。実務的にはほぼ常に workflow レベルで permissions: {} を設定して既定権限を全て落としておき、必要な job レベルで個別に permissions を付与するのが望ましいです。

caller の workflow レベルは {} に絞り、必要権限は reusable workflow を呼び出す jobs.deploy の job レベルに移します。これで「スコープは最小」「caller→callee の権限継承も維持」を両立できます。なお reusable workflow を呼ぶ場合、callee 側で要求される permissions は caller の job レベル permissions の範囲内に収まっている必要があるため、caller workflow レベルを {} にしただけで callee 側の権限まで落としてしまうと permissions cannot be granted to the called workflow 系のエラーになる点に注意。

修正後
- permissions:
-   id-token: write
-   contents: read
+ permissions: {}

  jobs:
    deploy:
+     permissions:
+       id-token: write # AWS IAM Role に OIDC AssumeRole するため reusable workflow に継承
+       contents: read
      uses: ./.github/workflows/reusable-deploy.yaml
補足: `permissions: {}` 自体を省略するとどうなるか

実際に permissions: {} をコメントアウトして zizmor を回してみると、別の audit がちゃんと検出してくれます。

$ zizmor --persona auditor .github/workflows/deploy.yaml
 INFO zizmor: 🌈 zizmor v1.24.1
 INFO audit: zizmor: 🌈 completed .github/workflows/deploy.yaml
warning[excessive-permissions]: overly broad permissions
  --> .github/workflows/deploy.yaml:1:1
   |
 1 | / name: Deploy
 2 | |
 3 | | on:
 4 | |   push:
...  |
36 | |       CLOUDINARY_CLOUD_NAME: ${{ secrets.CLOUDINARY_CLOUD_NAME }}
37 | |       CLOUDINARY_API_KEY: ${{ secrets.CLOUDINARY_API_KEY }}
   | |____________________________________________________________^ default permissions used due to no permissions: block
   |
   = note: audit confidence Medium

1 finding: 0 informational, 0 low, 1 medium, 0 high

severity は medium / confidence Medium だが、「workflow に permissions: の意思表明が無い」状態を別のメッセージで拾ってくれる挙動は、デフォルト権限のフォールバックを見逃したくない用途で便利です。

対応(#2): help[undocumented-permissions]

permissions: ブロックに各権限の意図を示すコメントが無いという、--pedantic 限定のコード品質/保守性チェックです。

https://github.com/shuntaka9576/shuntaka-dev/blob/018f7f4b7af7de390b9e78d368422f1d1b37f88f/.github/workflows/deploy.yaml#L19-L21

zizmorの定義は以下

https://github.com/zizmorcore/zizmor/blob/4f70a67a48f4f08c986de63922d181b14c199607/docs/audits.md#L1731-L1774

明示的な permissions: ブロックには各権限の目的をコメントで残すことを推奨します。十分にドキュメント化された permissions は過剰スコープを未然に防ぎ、ワークフローを保守しやすくします。contents: read は自明なため指摘対象外です。

本ファイルでは対応(#1) で workflow レベルの permissions:{} に絞ったため、workflow レベルの本指摘は同時に解消します。ドキュメントの通り、権限の付与に対して明示的にコメントを残すルールは非常に有用と感じました。

修正後対応

全て適用後再度確認し、指摘事項が見つからないことを確認しました。

$ zizmor --persona auditor .github/workflows/deploy.yaml

 INFO zizmor: 🌈 zizmor v1.24.1
 INFO audit: zizmor: 🌈 completed .github/workflows/deploy.yaml
No findings to report. Good job!

すでに解説済みの指摘も含めて最終的な差分は以下となります。

https://github.com/shuntaka9576/shuntaka-dev/commit/d05cb57a88c584403a0c55006179f11794f025a8

解析結果: デプロイのReusable Workflow

サマリ

単体実行: zizmor --persona auditor .github/workflows/reusable-deploy.yaml — 7 findings (2 fixable)
$ zizmor --persona auditor .github/workflows/reusable-deploy.yaml
 INFO zizmor: 🌈 zizmor v1.24.1
 INFO audit: zizmor: 🌈 completed .github/workflows/reusable-deploy.yaml
warning[artipacked]: credential persistence through GitHub Actions artifacts
  --> .github/workflows/reusable-deploy.yaml:28:9
   |
28 |       - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ does not set persist-credentials: false
   |
   = note: audit confidence Low
   = note: this finding has an auto-fix
   = help: audit documentation https://docs.zizmor.sh/audits/#artipacked

warning[excessive-permissions]: overly broad permissions
  --> .github/workflows/reusable-deploy.yaml:1:1
   |
 1 | / name: Deploy (Reusable)
 2 | |
 3 | | on:
 4 | |   workflow_call:
...  |
49 | |           CLOUDINARY_API_KEY: ${{ secrets.CLOUDINARY_API_KEY }}
50 | |           CLOUDINARY_API_SECRET_KEY_NAME: ${{ vars.CLOUDINARY_API_SECRET_KEY_NAME }}
   | |_____________________________________________________________________________________^ default permissions used due to no permissions: block
   |
   = note: audit confidence Medium
   = help: audit documentation https://docs.zizmor.sh/audits/#excessive-permissions

help[template-injection]: code injection via template expansion
  --> .github/workflows/reusable-deploy.yaml:43:35
   |
43 | ...   run: bunx cdk deploy "${{ inputs.stageName == 'prd' && 'p' || 'd' }}-st-main" -c stageName=${{ inputs.stageName }} --require-a...
   |       --- this run block        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ may expand into attacker-controllable code
   |
   = note: audit confidence High
   = help: audit documentation https://docs.zizmor.sh/audits/#template-injection

error[template-injection]: code injection via template expansion
  --> .github/workflows/reusable-deploy.yaml:43:104
   |
43 |         run: bunx cdk deploy "${{ inputs.stageName == 'prd' && 'p' || 'd' }}-st-main" -c stageName=${{ inputs.stageName }} --require...
   |         --- this run block                                                                             ^^^^^^^^^^^^^^^^ may expand into attacker-controllable code
   |
   = note: audit confidence High
   = note: this finding has an auto-fix
   = help: audit documentation https://docs.zizmor.sh/audits/#template-injection

warning[self-hosted-runner]: runs on a self-hosted runner
  --> .github/workflows/reusable-deploy.yaml:21:5
   |
21 |     runs-on: [self-hosted, macOS, ARM64]
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ self-hosted runner used here
   |
   = note: audit confidence High
   = help: audit documentation https://docs.zizmor.sh/audits/#self-hosted-runner

help[undocumented-permissions]: permissions without explanatory comments
  --> .github/workflows/reusable-deploy.yaml:25:7
   |
25 |       id-token: write
   |       ^^^^^^^^^^^^^^^ needs an explanatory comment
   |
   = note: audit confidence High
   = help: audit documentation https://docs.zizmor.sh/audits/#undocumented-permissions

info[anonymous-definition]: workflow or action definition without a name
  --> .github/workflows/reusable-deploy.yaml:20:3
   |
20 |   deploy:
   |   ^^^^^^ this job
   |
   = note: audit confidence High
   = tip: use 'name: ...' to give this job a name
   = help: audit documentation https://docs.zizmor.sh/audits/#anonymous-definition

7 findings (2 fixable): 1 informational, 2 low, 3 medium, 1 high

https://github.com/shuntaka9576/shuntaka-dev/blob/018f7f4b7af7de390b9e78d368422f1d1b37f88f/.github/workflows/reusable-deploy.yaml

# severity confidence 該当行 persona Auto-fix 概要 エラーメッセージの内容
1 error High L43 regular, pedantic, auditor あり run: 内で ${{ inputs.stageName }} を直接展開しており、コマンド注入されうる。env: 経由で渡すべき error[template-injection]: code injection via template expansion
may expand into attacker-controllable code
2 warning Medium L1-L50 pedantic, auditor なし permissions: ブロック未設定のため、デフォルトの広い permissions が使われる warning[excessive-permissions]: overly broad permissions
default permissions used due to no permissions: block
3 warning High L21 auditor なし self-hosted runner を使用(GitHub-hosted より攻撃面が広い点に注意) warning[self-hosted-runner]: runs on a self-hosted runner
self-hosted runner used here
4 warning Low L28 regular, pedantic, auditor あり actions/checkoutpersist-credentials: false 未設定 warning[artipacked]: credential persistence through GitHub Actions artifacts
does not set persist-credentials: false
5 info High L20 pedantic, auditor なし deploy ジョブに name: が設定されていない info[anonymous-definition]: workflow or action definition without a name
this job
6 help High L43 pedantic, auditor なし run: 内で ${{ inputs.stageName == 'prd' && 'p' || 'd' }} を直接展開しており、入力次第でコマンド注入されうる help[template-injection]: code injection via template expansion
may expand into attacker-controllable code
7 help High L25 pedantic, auditor なし id-token: write に説明コメントが無い help[undocumented-permissions]: permissions without explanatory comments
needs an explanatory comment

対応(#1): error[template-injection]

run: の文字列の中に ${{ inputs.stageName }} を直接展開しています。GitHub Actions のテンプレート展開はシェルや引用符を理解しない単純な文字列置換で、入力次第で任意のシェルコマンドが組み込まれてしまいます。

https://github.com/shuntaka9576/shuntaka-dev/blob/018f7f4b7af7de390b9e78d368422f1d1b37f88f/.github/workflows/reusable-deploy.yaml#L41-L44

zizmorの定義は以下

https://github.com/zizmorcore/zizmor/blob/4f70a67a48f4f08c986de63922d181b14c199607/docs/audits.md#L1641-L1729

もっとも一般的な template injection は run: などコード実行ブロック内に現れます。これらのケースでは、インラインのテンプレート展開を、展開結果を値に持つ環境変数で置き換えるのが定石です。これにより脆弱性は回避できます。シェル変数の展開は通常の quoting / expansion ルールに従うためです。なお、${{ env.VARNAME }} は依然テンプレート展開なので、必ず ${VARNAME} でシェル側に展開させてください。

stageNameenv: 経由でシェル環境変数に渡し、run: 内ではシェル変数として参照します。三項演算 ${{ inputs.stageName == 'prd' && 'p' || 'd' }} も同じ理由で書き換え、シェル側の case で prefix を作る形に直します。

修正後
      - name: CDK Deploy
        working-directory: iac/aws
-       run: bunx cdk deploy "${{ inputs.stageName == 'prd' && 'p' || 'd' }}-st-main"
-         -c stageName=${{ inputs.stageName }} --require-approval never
+       env:
+         STAGE_NAME: ${{ inputs.stageName }}
+       run: |
+         case "$STAGE_NAME" in
+           prd) PREFIX=p ;;
+           *)   PREFIX=d ;;
+         esac
+         bunx cdk deploy "${PREFIX}-st-main" -c "stageName=${STAGE_NAME}" --require-approval never

これにより #6 の help[template-injection](同 audit の三項演算側 col 35 検出)も同時に解消します。

対応(#2): warning[excessive-permissions]

reusable-deploy.yaml には workflow レベルの permissions: 宣言が無いため、デフォルト権限が GITHUB_TOKEN に付与されてしまいます。callee 側にも permissions: {} を置いて、別 caller から呼ばれた場合にもデフォルト権限に依存しない形にします。必要権限は既に jobs.deploy.permissions: で宣言済みなので、追加するのは workflow レベルの {} だけです。

修正後
  on:
    workflow_call:
      ...

+ permissions: {}
+
  jobs:
    deploy:
      ...
      permissions:
        id-token: write
        contents: read

対応(#3): warning[self-hosted-runner]

self-hosted runner は永続ホストのため、GitHub-hosted runner には無い攻撃面があります。

  • 過去ジョブの残骸: 前回ジョブが残した認証情報、キャッシュ、依存パッケージなどを後続ジョブが読み取り・改ざんできる
  • ネットワーク到達範囲: ホストの設置場所次第で社内ネットワークや IAM ロールに到達できるケースがあり、ジョブを乗っ取られた際の被害範囲が広くなる

https://github.com/shuntaka9576/shuntaka-dev/blob/018f7f4b7af7de390b9e78d368422f1d1b37f88f/.github/workflows/reusable-deploy.yaml#L19-L21

zizmorの定義は以下

https://github.com/zizmorcore/zizmor/blob/4f70a67a48f4f08c986de63922d181b14c199607/docs/audits.md#L1503-L1548

原則として、セルフホストランナーの使用はプライベートリポジトリのみに留めるべきです。
不特定多数が利用できるパブリックリポジトリにセルフホストランナーを公開することは、例外なくセキュリティリスクを伴います。

実際には、ホストのカスタム構成が必要な場合など、パブリックリポジトリでセルフホストランナーを使用せざるを得ないケースも多々あります。そのような場合には、以下の対策を講じることでリスクを最小限に抑えることができます。

  1. 外部コントリビューターによるワークフロー実行には手動承認を必須にする
    この設定は、リポジトリ、ワークフロー、またはエンタープライズ単位で行うことができます。詳細は GitHubのドキュメント を参照してください。

  2. エフェメラル(ジャストインタイム)ランナー のみを使用する
    これらのランナーは、一つのジョブを実行するためだけにその都度作成され、終了後すぐに破棄されます。これにより、攻撃者がシステム内に潜伏し続ける(持続性を維持する)ことを困難(不可能ではありませんが)にします。

このうち (1) は GitHub の Settings → Actions → General → "Approval for running fork pull request workflows from contributors" で設定します。選べる 3 段階は次の通り。

設定 承認が必要なユーザー 承認なしで実行できるユーザー
Require approval for first-time contributors who are new to GitHub GitHub アカウント自体が新しく、かつ本リポジトリへの merge 実績も無いユーザー 上記以外(GitHub 古参であれば本リポジトリ初コントリビュータでも素通り)
Require approval for first-time contributors(デフォルト) 本リポジトリにまだ commit / PR がマージされていないユーザー 一度でも PR / commit がマージ済みのユーザー
Require approval for all external contributors リポジトリの member / owner 以外全員 リポジトリの member / owner のみ

デフォルト設定: Require approval for first-time contributors が選択されている
変更前

self-hosted runner を晒している状況では、過去に PR を 1 回通したアカウント(およびそのアカウントの乗っ取り)経由で runner ホストにジョブを流される余地が残るため、一番厳しい "Require approval for all external contributors"(リポジトリの member / owner 以外は全員承認必須)に変更しました。

変更後: Require approval for all external contributors を選択して Save
変更後

本リポジトリは Apple Silicon ビルド用に macOS ARM64 の self-hosted runner を使用。callee は workflow_call 専用で、caller(deploy.yaml)のトリガを push: [preview, main] / workflow_dispatch に限定しているため、fork PR のコードが self-hosted runner に到達する経路は「PR レビュー → preview / main へのマージ → その後の push トリガ」だけになります。実質的にマージレビューが人間ゲートとして機能している前提のため、runs-on: 直上にコメントで意図を残し、warning は受容します。

修正後
    jobs:
      deploy:
+       # Apple Silicon ビルド用 self-hosted runner。呼び出し元のトリガ制限で pull_request 由来では起動しない。
-       runs-on: [self-hosted, macOS, ARM64]
+       runs-on: [self-hosted, macOS, ARM64] # zizmor: ignore[self-hosted-runner]

対応(#7): help[undocumented-permissions]

jobs.deploy.permissions:id-token: write に説明コメントが無い、という指摘です。zizmor は 同一行のトレイリングコメント を要求するため、permissions: ブロックの直前や id-token: write の上の行にコメントを置いても検出されたままになります。

修正後
      permissions:
-       id-token: write
+       id-token: write # AWS IAM Role に OIDC AssumeRole するため
        contents: read

(#4 artipacked / #5 anonymous-definition は他章の対応で説明済みのためスキップ。#6 template-injection は #1 の修正で同時解消。)

修正後対応

全て適用後再度確認し、指摘事項が見つからないことを確認しました。

$ zizmor --persona auditor .github/workflows/reusable-deploy.yaml
 INFO zizmor: 🌈 zizmor v1.24.1
 INFO audit: zizmor: 🌈 completed .github/workflows/reusable-deploy.yaml
No findings to report. Good job! (1 ignored)

すでに解説済みの指摘も含めて最終的な差分は以下となります。

https://github.com/shuntaka9576/shuntaka-dev/commit/213a50c8940ed6adf3c7c14f291b34031d4b4a28

解析結果: Sphinxドキュメントのデプロイ

サマリ

単体実行: zizmor --persona auditor .github/workflows/docs.yaml — 6 findings (1 fixable)
$ zizmor --persona auditor .github/workflows/docs.yaml
 INFO zizmor: 🌈 zizmor v1.24.1
 INFO audit: zizmor: 🌈 completed .github/workflows/docs.yaml
warning[artipacked]: credential persistence through GitHub Actions artifacts
  --> .github/workflows/docs.yaml:29:9
   |
29 |         - name: Checkout
   |  _________^
30 | |         uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
31 | |         with:
32 | |           fetch-depth: 0
   | |________________________^ does not set persist-credentials: false
   |
   = note: audit confidence Low
   = note: this finding has an auto-fix
   = help: audit documentation https://docs.zizmor.sh/audits/#artipacked

error[excessive-permissions]: overly broad permissions
  --> .github/workflows/docs.yaml:17:3
   |
17 |   pages: write
   |   ^^^^^^^^^^^^ pages: write is overly broad at the workflow level
   |
   = note: audit confidence High
   = help: audit documentation https://docs.zizmor.sh/audits/#excessive-permissions

error[excessive-permissions]: overly broad permissions
  --> .github/workflows/docs.yaml:18:3
   |
18 |   id-token: write
   |   ^^^^^^^^^^^^^^^ id-token: write is overly broad at the workflow level
   |
   = note: audit confidence High
   = help: audit documentation https://docs.zizmor.sh/audits/#excessive-permissions

help[undocumented-permissions]: permissions without explanatory comments
  --> .github/workflows/docs.yaml:17:3
   |
17 |   pages: write
   |   ^^^^^^^^^^^^ needs an explanatory comment
18 |   id-token: write
   |   ^^^^^^^^^^^^^^^ needs an explanatory comment
   |
   = note: audit confidence High
   = help: audit documentation https://docs.zizmor.sh/audits/#undocumented-permissions

info[anonymous-definition]: workflow or action definition without a name
  --> .github/workflows/docs.yaml:25:3
   |
25 |   build:
   |   ^^^^^ this job
   |
   = note: audit confidence High
   = tip: use 'name: ...' to give this job a name
   = help: audit documentation https://docs.zizmor.sh/audits/#anonymous-definition

info[anonymous-definition]: workflow or action definition without a name
  --> .github/workflows/docs.yaml:68:3
   |
68 |   deploy:
   |   ^^^^^^ this job
   |
   = note: audit confidence High
   = tip: use 'name: ...' to give this job a name
   = help: audit documentation https://docs.zizmor.sh/audits/#anonymous-definition

6 findings (1 fixable): 2 informational, 1 low, 1 medium, 2 high

こちらはよくある Sphinx のドキュメントをGitHub PagesにデプロイするGitHub Actionsです。

https://github.com/shuntaka9576/shuntaka-dev/blob/018f7f4b7af7de390b9e78d368422f1d1b37f88f/.github/workflows/docs.yaml

# severity confidence 該当行 persona Auto-fix 概要 エラーメッセージの内容
1 error High L17 regular, pedantic, auditor なし workflow レベルで pages: write を付与しており、全ジョブが Pages を更新できる error[excessive-permissions]: overly broad permissions
pages: write is overly broad at the workflow level
2 error High L18 regular, pedantic, auditor なし workflow レベルで id-token: write を付与しており、全ジョブが OIDC トークンを発行できる error[excessive-permissions]: overly broad permissions
id-token: write is overly broad at the workflow level
3 warning Low L29-L32 regular, pedantic, auditor あり actions/checkoutpersist-credentials: false 未設定(fetch-depth: 0 で全履歴取得しているので影響大) warning[artipacked]: credential persistence through GitHub Actions artifacts
does not set persist-credentials: false
4 info High L25 pedantic, auditor なし build ジョブに name: が設定されていない info[anonymous-definition]: workflow or action definition without a name
this job
5 info High L68 pedantic, auditor なし deploy ジョブに name: が設定されていない info[anonymous-definition]: workflow or action definition without a name
this job
6 help High L17-L18 pedantic, auditor なし pages: write / id-token: write に説明コメントが無い help[undocumented-permissions]: permissions without explanatory comments
needs an explanatory comment

修正後対応

本ワークフローで検出された 6 件はいずれも CI / デプロイ章で扱った audit type と重複するため、説明と修正は対応する章を参照してください。

# audit 参照先
1, 2 excessive-permissions デプロイ: 対応(#1)
3 artipacked CI: 対応(#1)
4, 5 anonymous-definition CI: 対応(#2)
6 undocumented-permissions デプロイ: 対応(#2)

すでに解説済みの指摘も含めて最終的な差分は以下となります。

https://github.com/shuntaka9576/shuntaka-dev/commit/64d92e52eb236c45458e1bf43ec1d5bbc4b75dc7

解析結果: Renovate契機のCargo.lock更新

サマリ

単体実行: zizmor --persona auditor .github/workflows/renovate-cargo-update.yaml — 6 findings (2 fixable)

こちらは、RenovateでCargo.tomlの更新を契機にCargo.lockを更新するワークフローです。Renovate本体でCargo.lockまで一括更新してくれれば不要になりますが、現状はサポート待ちのためワークフローで補っています。次節の microsoft/apm も同じ理由です。

$ zizmor --persona auditor .github/workflows/renovate-cargo-update.yaml
 INFO zizmor: 🌈 zizmor v1.24.1
 INFO audit: zizmor: 🌈 completed .github/workflows/renovate-cargo-update.yaml
warning[artipacked]: credential persistence through GitHub Actions artifacts
  --> .github/workflows/renovate-cargo-update.yaml:18:9
   |
18 |         - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
   |  _________^
19 | |         with:
20 | |           ref: ${{ github.head_ref }}
   | |_____________________________________^ does not set persist-credentials: false
   |
   = note: audit confidence Low
   = note: this finding has an auto-fix
   = help: audit documentation https://docs.zizmor.sh/audits/#artipacked

error[excessive-permissions]: overly broad permissions
  --> .github/workflows/renovate-cargo-update.yaml:10:3
   |
10 |   contents: write
   |   ^^^^^^^^^^^^^^^ contents: write is overly broad at the workflow level
   |
   = note: audit confidence High
   = help: audit documentation https://docs.zizmor.sh/audits/#excessive-permissions

help[undocumented-permissions]: permissions without explanatory comments
  --> .github/workflows/renovate-cargo-update.yaml:10:3
   |
10 |   contents: write
   |   ^^^^^^^^^^^^^^^ needs an explanatory comment
   |
   = note: audit confidence High
   = help: audit documentation https://docs.zizmor.sh/audits/#undocumented-permissions

error[bot-conditions]: spoofable bot actor check
  --> .github/workflows/renovate-cargo-update.yaml:14:9
   |
13 |   update-and-ci:
   |   ------------- this job
14 |     if: github.actor == 'renovate[bot]'
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ actor context may be spoofable
   |
   = note: audit confidence High
   = note: this finding has an auto-fix
   = help: audit documentation https://docs.zizmor.sh/audits/#bot-conditions

info[anonymous-definition]: workflow or action definition without a name
  --> .github/workflows/renovate-cargo-update.yaml:13:3
   |
13 |   update-and-ci:
   |   ^^^^^^^^^^^^^ this job
   |
   = note: audit confidence High
   = tip: use 'name: ...' to give this job a name
   = help: audit documentation https://docs.zizmor.sh/audits/#anonymous-definition

help[concurrency-limits]: insufficient job-level concurrency limits
  --> .github/workflows/renovate-cargo-update.yaml:3:1
   |
 3 | / on:
 4 | |   pull_request:
 5 | |     paths:
 6 | |       - 'Cargo.toml'
 7 | |       - 'apps/blog-api/**/Cargo.toml'
   | |_____________________________________^ workflow is missing concurrency setting
...
13 |     update-and-ci:
   |     ------------- job affected by missing workflow concurrency
   |
   = note: audit confidence High
   = help: audit documentation https://docs.zizmor.sh/audits/#concurrency-limits

6 findings (2 fixable): 1 informational, 2 low, 1 medium, 2 high

https://github.com/shuntaka9576/shuntaka-dev/blob/018f7f4b7af7de390b9e78d368422f1d1b37f88f/.github/workflows/renovate-cargo-update.yaml

# severity confidence 該当行 persona Auto-fix 概要 エラーメッセージの内容
1 error High L10 pedantic, auditor なし workflow レベルで contents: write を付与しており全ジョブが書き換え可能 error[excessive-permissions]: overly broad permissions
contents: write is overly broad at the workflow level
2 error High L14 regular, pedantic, auditor あり github.actor == 'renovate[bot]' は spoof 可能 error[bot-conditions]: spoofable bot actor check
actor context may be spoofable
3 warning Low L18-L20 regular, pedantic, auditor あり actions/checkoutpersist-credentials: false 未設定(PR head checkout) warning[artipacked]: credential persistence through GitHub Actions artifacts
does not set persist-credentials: false
4 info High L13 pedantic, auditor なし update-and-ci ジョブに name: が設定されていない info[anonymous-definition]: workflow or action definition without a name
this job
5 help High L10 pedantic, auditor なし contents: write に説明コメントが無い help[undocumented-permissions]: permissions without explanatory comments
needs an explanatory comment
6 help High L3-L7 pedantic, auditor なし workflow に concurrency 設定が無い help[concurrency-limits]: insufficient job-level concurrency limits
workflow is missing concurrency setting

対応(#2): error[bot-conditions]

https://github.com/shuntaka9576/shuntaka-dev/blob/018f7f4b7af7de390b9e78d368422f1d1b37f88f/.github/workflows/renovate-cargo-update.yaml#L13-L14

zizmorの定義は以下

https://github.com/zizmorcore/zizmor/blob/4f70a67a48f4f08c986de63922d181b14c199607/docs/audits.md#L182-L254

一般的に、github.actor を使って実行者の正当性を確認するだけでは不十分です。ほとんどの場合、github.event.pull_request.user.login などを使用すべきです。なぜなら、このコンテキストはプルリクエストを最後に変更した人ではなく、プルリクエストを「作成した」本人を指すからです。

本ワークフローは if: github.actor == 'renovate[bot]' で「Renovate Bot による実行か」を判定していますが、github.actor はプルリクエストを最後に変更した人を指すだけで、プルリクエストを作成した本人ではありません。攻撃者は HEAD コミットだけ renovate[bot] 名義で push し、その先祖に攻撃コードを混ぜ込むことで github.actor によるチェックをすり抜けられます。on: pull_request トリガなので、プルリクエストを作成した本人を指す github.event.pull_request.user.login で置き換えます。

なお renovate[bot] という login は GitHub App としての Renovate(https://github.com/apps/renovate)をリポジトリにインストールしている場合の名前です。Self-hosted Renovate や PAT 経由で動かしている場合は別の login になるため、gh pr view <PR> --json author などで実際の author を確認してから値を合わせてください。

修正後
  jobs:
    update-and-ci:
-     if: github.actor == 'renovate[bot]'
+     if: github.event.pull_request.user.login == 'renovate[bot]'

修正後対応

本セクションで扱った #2 以外の 5 件は他章の対応で説明済みのため、参照先は以下の通り。

# audit 参照先
1 excessive-permissions デプロイ: 対応(#1)
3 artipacked CI: 対応(#1)
4 anonymous-definition CI: 対応(#2)
5 undocumented-permissions デプロイ: 対応(#2)
6 concurrency-limits CI: 対応(#3)

全て適用後再度確認し、指摘事項が見つからないことを確認しました。

$ zizmor --persona auditor .github/workflows/renovate-cargo-update.yaml
 INFO zizmor: 🌈 zizmor v1.24.1
 INFO audit: zizmor: 🌈 completed .github/workflows/renovate-cargo-update.yaml
No findings to report. Good job!

すでに解説済みの指摘も含めて最終的な差分は以下となります。

https://github.com/shuntaka9576/shuntaka-dev/commit/d0a12c3253716634a4916f82b39fc80767bed03d

解析結果: Renovate契機のmicrosoft/apmのlock更新

サマリ

単体実行: zizmor --persona auditor .github/workflows/renovate-apm-update.yaml — 6 findings (2 fixable)
$ zizmor --persona auditor .github/workflows/renovate-apm-update.yaml
 INFO zizmor: 🌈 zizmor v1.24.1
 INFO audit: zizmor: 🌈 completed .github/workflows/renovate-apm-update.yaml
warning[artipacked]: credential persistence through GitHub Actions artifacts
  --> .github/workflows/renovate-apm-update.yaml:20:9
   |
20 |         - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
   |  _________^
21 | |         with:
22 | |           ref: ${{ github.head_ref }}
   | |_____________________________________^ does not set persist-credentials: false
   |
   = note: audit confidence Low
   = note: this finding has an auto-fix
   = help: audit documentation https://docs.zizmor.sh/audits/#artipacked

error[excessive-permissions]: overly broad permissions
 --> .github/workflows/renovate-apm-update.yaml:9:3
  |
9 |   contents: write
  |   ^^^^^^^^^^^^^^^ contents: write is overly broad at the workflow level
  |
  = note: audit confidence High
  = help: audit documentation https://docs.zizmor.sh/audits/#excessive-permissions

help[undocumented-permissions]: permissions without explanatory comments
 --> .github/workflows/renovate-apm-update.yaml:9:3
  |
9 |   contents: write
  |   ^^^^^^^^^^^^^^^ needs an explanatory comment
  |
  = note: audit confidence High
  = help: audit documentation https://docs.zizmor.sh/audits/#undocumented-permissions

error[bot-conditions]: spoofable bot actor check
  --> .github/workflows/renovate-apm-update.yaml:13:9
   |
12 |   update-and-audit:
   |   ---------------- this job
13 |     if: github.actor == 'renovate[bot]'
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ actor context may be spoofable
   |
   = note: audit confidence High
   = note: this finding has an auto-fix
   = help: audit documentation https://docs.zizmor.sh/audits/#bot-conditions

info[anonymous-definition]: workflow or action definition without a name
  --> .github/workflows/renovate-apm-update.yaml:12:3
   |
12 |   update-and-audit:
   |   ^^^^^^^^^^^^^^^^ this job
   |
   = note: audit confidence High
   = tip: use 'name: ...' to give this job a name
   = help: audit documentation https://docs.zizmor.sh/audits/#anonymous-definition

help[concurrency-limits]: insufficient job-level concurrency limits
  --> .github/workflows/renovate-apm-update.yaml:3:1
   |
 3 | / on:
 4 | |   pull_request:
 5 | |     paths:
 6 | |       - 'apm.yml'
   | |_________________^ workflow is missing concurrency setting
...
12 |     update-and-audit:
   |     ---------------- job affected by missing workflow concurrency
   |
   = note: audit confidence High
   = help: audit documentation https://docs.zizmor.sh/audits/#concurrency-limits

6 findings (2 fixable): 1 informational, 2 low, 1 medium, 2 high

https://github.com/shuntaka9576/shuntaka-dev/blob/018f7f4b7af7de390b9e78d368422f1d1b37f88f/.github/workflows/renovate-apm-update.yaml

# severity confidence 該当行 persona Auto-fix 概要 エラーメッセージの内容
1 error High L9 pedantic, auditor なし workflow レベルで contents: write を付与しており、全ジョブがリポジトリ書き換え可能 error[excessive-permissions]: overly broad permissions
contents: write is overly broad at the workflow level
2 error High L13 regular, pedantic, auditor あり github.actor == 'renovate[bot]' は spoof 可能(実行者は別人でも actor を装える)。github.event.sender 等を使うべき error[bot-conditions]: spoofable bot actor check
actor context may be spoofable
3 warning Low L20-L22 regular, pedantic, auditor あり actions/checkoutpersist-credentials: false 未設定(PR head を checkout しているので特に注意) warning[artipacked]: credential persistence through GitHub Actions artifacts
does not set persist-credentials: false
4 info High L12 pedantic, auditor なし update-and-audit ジョブに name: が設定されていない info[anonymous-definition]: workflow or action definition without a name
this job
5 help High L9 pedantic, auditor なし contents: write に説明コメントが無い help[undocumented-permissions]: permissions without explanatory comments
needs an explanatory comment
6 help High L3-L6 pedantic, auditor なし workflow に concurrency 設定が無い help[concurrency-limits]: insufficient job-level concurrency limits
workflow is missing concurrency setting

修正後対応

本ワークフローで検出された 6 件はいずれも CI / デプロイ / Renovate契機のCargo.lock更新 章で扱った audit type と重複するため、説明と修正は対応する章を参照してください。

# audit 参照先
1 excessive-permissions デプロイ: 対応(#1)
2 bot-conditions Renovate(Cargo): 対応(#2)
3 artipacked CI: 対応(#1)
4 anonymous-definition CI: 対応(#2)
5 undocumented-permissions デプロイ: 対応(#2)
6 concurrency-limits CI: 対応(#3)

すでに解説済みの指摘も含めて最終的な差分は以下となります。

https://github.com/shuntaka9576/shuntaka-dev/commit/cd9af10309086714dc0871bf9ab3c90305045a2a

さいごに

全 6 ワークフローを --persona auditor で通し、self-hosted runner の意図的な ignore 1 件を除いて対応しました。

confidence の指標のおかげで、偽陽性かどうかの判断が付きやすく便利です。auditor まで上げても明らかに不要な対応は全く無い印象で、ノイズに埋もれず全件向き合う価値があるツールだと感じました。

脚注
  1. ファイルごとに表を分割した。各表の中は severity(error > warning > info > help)順。「persona」列はその指摘を検出する persona のリスト。デフォルト persona は regular なので、列に regular が含まれていればオプションなしの zizmor .github でも検出される。 ↩︎

この記事をシェアする

関連記事