Securely Specifying GitHub Actions Action Versions — From Hash Values and Immutable Tags to Workflow-Level Dependency Locking

Securely Specifying GitHub Actions Action Versions — From Hash Values and Immutable Tags to Workflow-Level Dependency Locking

# GitタグのMutability(書き換えリスク)への対策 ## tj-actionsインシデントの概要 2025年3月、`tj-actions/changed-files`のGitタグが悪意あるコードを含むコミットに書き換えられ、CIパイプラインでシークレットが窃取されるサプライチェーン攻撃が発生した。 --- ## 根本原因:Mutableなタグへの依存 ```yaml # 危険な参照方式 - uses: tj-actions/changed-files@v45 # タグは上書き可能 - uses: actions/checkout@main # ブランチは常に変動 ``` --- ## 対策1:コミットSHAによる固定参照(最重要) ```yaml # 安全な参照方式(フルSHAで固定) - uses: tj-actions/changed-files@d6e91a2266cdb7aa5e86d4609b6ee88df5e0c612 # v45.0.7 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 ``` ### SHAの取得方法 ```bash # タグに対応するコミットSHAを取得 git ls-remote https://github.com/actions/checkout refs/tags/v4.2.2 # annotated tagの場合はderefが必要(^{}) # 出力例: # abc123... refs/tags/v4.2.2 # def456... refs/tags/v4.2.2^{} ← こちらを使用 ``` --- ## 対策2:依存関係の自動更新ツール ### Dependabot ```yaml # .github/dependabot.yml version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" groups: actions: patterns: - "*" ``` → SHA固定していてもPRで新バージョンのSHAを自動提案 ### Renovate ```json { "extends": ["config:base"], "github-actions": { "pinDigests": true } } ``` --- ## 対策3:許可リスト(Allowlist)の管理 ### OpenSSF Scorecard + policy ```yaml # .github/workflows/scorecard.yml - name: Run Scorecard uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75b087807c with: results_format: sarif ``` ### Actionlint による静的解析 ```bash # CIでlintを実行 actionlint # タグ参照を検出してエラー # error: action ref must be a full SHA ``` --- ## 対策4:OIDC・Sigstore による署名検証 ```bash # GitHub Actions成果物の署名検証(gh attestation) gh attestation verify artifact.tar.gz \ --owner myorg \ --bundle artifact.tar.gz.sigstore ``` ### Reusable Workflowsの活用 ```yaml # 自社管理のワークフローを経由させる jobs: build: uses: myorg/central-workflows/.github/workflows/build.yml@abc123sha ``` --- ## 対策5:ネットワーク・権限の最小化 ```yaml jobs: build: permissions: contents: read # 必要最小限に id-token: write # OIDC使用時のみ # 外部へのアクセス制限 env: ACTIONS_RUNNER_DEBUG: false ``` ### Egress filtering(外部通信の制限) ```yaml # StepSecurityのHarden-Runnerを活用 - uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 with: egress-policy: block allowed-endpoints: > api.github.com:443 registry.npmjs.org:443 ``` --- ## 対策6:インベントリ管理と監査 ```bash # リポジトリ内の全Action参照を一覧化 grep -r "uses:" .github/workflows/ | \ grep -v "@[0-9a-f]\{40\}" | \ grep -v "^#" # SHA固定されていない参照を抽出 ``` ### OpenSSF Scorecard の確認項目 | チェック項目 | 内容 | |---|---| | Pinned-Dependencies | SHA固定されているか | | Token-Permissions | 権限が最小化されているか | | Dangerous-Workflow | 危険なパターンがないか | --- ## 対策まとめ ``` 優先度 高 ├── 全ActionをフルコミットSHAで固定 ├── Dependabot/RenovateでSHAの自動更新 └── harden-runnerでEgress制限 優先度 中 ├── actionlintをCIに組み込む ├── 権限をminimum privilegeに └── Scorecardで定期監査 優先度 低(追加防御) ├── Sigstoreによる署名検証 ├── Reusable Workflowsの集中管理 └── Forkして自組織管理 ``` --- ## 参考ツール - [StepSecurity Action Advisor](https://app.stepsecurity.io/) - SHA自動変換 - [pin-github-action](https://github.com/mheap/pin-github-action) - 一括SHA固定 - [actionlint](https://github.com/rhysd/actionlint) - 静的解析 - [OpenSSF Scorecard](https://securityscorecards.dev/) - セキュリティスコア評価
2026.05.18

This page has been translated by machine translation. View original

In the tj-actions/changed-files compromise incident that occurred in March 2025 (CVE-2025-30066), version tags were rewritten, once again highlighting the importance of specifying actions securely.

This article explains the following two approaches that are already available as countermeasures:

  • Commit hash
  • Immutable tag

And also covers:

  • Workflow-Level Dependency Locking

which is announced for release within 2026.

The Problem with Naive Specification

Specifications like uses: owner/action@v4 that appear in GitHub Actions samples are convenient, but they have structural problems on both the provider and consumer sides.

Provider perspective

  • Git tags can be rewritten. They can be redirected to a different commit.
  • Major version tags are dynamic. Major tags like actions/checkout@v4 move every time a new minor/patch is released.

Consumer perspective

  • When the above happens, the reference target changes even though the version specification in the workflow file hasn't changed.

In short, specifications like uses: owner/action@v4 are convenient but not immutable.

There are officially two methods for creating references that cannot be substituted.

Pinning with a Commit Hash Value

This method involves writing @<Git commit SHA> directly. Git commit SHAs are guaranteed to be immutable.

- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11  # v4.1.1

Since the hash value alone doesn't tell you which version it is, this approach is paired with the practice of supplementing the version number in a comment.

Using tools like pinact, you can easily achieve version specification with hash values and comments.

https://dev.classmethod.jp/articles/hardening-github-actions-with-pinact-commit-sha-semver/

Tools such as Dependabot and Renovate, which update dependencies, also support updating hash values.

There are also options to enforce pinning actions to commit SHAs at the organization or repository level.

Note that for Impostor Commits, where commits are accumulated on a fork, it is necessary to use other tools such as zizmor in combination.

Using Immutable Tags

This method uses tags that support immutable releases, which GitHub made GA on October 28, 2025.

- uses: astral-sh/setup-uv@v8.1.0

At a glance, the configuration looks the same as before.

The list of releases for astral-sh/setup-uv shows the word "Immutable".

astral-immutable-tag

With immutable releases, a version once issued cannot be reused. If there is a problem with a release, it must be re-released as a new version, no matter how trivial the commit.

With the format v<Major>.<Minor>.<Patch>, providing major and minor versions like v8 or v8.0 creates a problem where version and resource are not in a 1:1 relationship.
For this reason, astral-sh/setup-uv and others have gone a step further, adopting a policy of not releasing major or minor versions from v8 onwards.

To increase security even more we will stop publishing minor tags. You won't be able to use @v8 or @v8.0 any longer. We do this because pinning to major releases opens up users to supply chain attacks like what happened to tj-actions.

(astral-sh/setup-uv release notes)

When updating

- uses: astral-sh/setup-uv@v7

instead of

- uses: astral-sh/setup-uv@v8

you must specify down to the patch version like

- uses: astral-sh/setup-uv@v8.1.0

or it won't work.

To enable immutable releases, go to the repository's Settings → General → Releases → check "Enable release immutability".

Next-Generation Workflow-Level Dependency Locking

GitHub announced a security roadmap in late March 2026.

https://github.blog/news-insights/product-news/whats-coming-to-our-github-actions-2026-security-roadmap/

Workflow-Level Dependency Locking, scheduled for release by September 2026, follows a model similar to Go's go.mod (version) + go.sum (checksum), where the uses: section declares the version and the new dependencies: section declares the version + hash value (meaning mismatches between version and hash value can also be detected). Just as go.sum covers transitive dependencies, this feature is planned to also cover nested dependencies such as composite actions.

name: build-and-attest

on:
  workflow_dispatch:

permissions:
  contents: read
  id-token: write
  attestations: write

jobs:
  build-and-attest:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: actions/attest-build-provenance@v3
        with:
          subject-path: README.md

dependencies:
  - github.com/actions/checkout@v6.0.1:sha1-8e8c483db84b4bee98b60c0593521ed34d9990e8
  - github.com/actions/attest-build-provenance@v3.1.0:sha1-00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8
  - github.com/actions/attest@v3.1.0:sha1-7667f588f2f73a90cea6c7ac70e78266c4f76616

Closing

The following methods are available for specifying GitHub Actions actions securely.

  1. Hash value pinning like actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
  2. Using immutable tags like astral-sh/setup-uv@v8.1.0 (when supported by the provider)
  3. A more robust mechanism similar to Go's go.mod + go.sum (Workflow-Level Dependency Locking) is planned for release within 2026

Since immutable release (tags) depend partly on the action provider, it is recommended to start with hash value pinning first if you want to prioritize consistency.

References

Share this article