Last weekend, the popular GitHub Action tj-actions/changed-files was compromised.

The issue was solved, but similar incidents could happen again in the future.
To prevent such issues, pinning action versions by full commit hash is recommended.

👉 GitHub Docs:

Pin actions to a full length commit SHA
Pinning an action to a full length commit SHA is currently the only way to use an action as an immutable release.
Pinning to a particular SHA helps mitigate the risk of a bad actor adding a backdoor to the action's repository, as they would need to generate a SHA-1 collision for a valid Git object payload.
When selecting a SHA, you should verify it is from the action's repository and not a repository fork.

This post introduces how to pin GitHub Action versions across all repositories in your organization.

pinact

You can pin GitHub Actions using a CLI tool called pinact.
It's so easy to use:

pinact run

If you want to fix composite actions and documents, you can specify file paths.

pinact run action.yaml README.md

You can also update actions using the -u option:

pinact run -u

For more details, check out the pinact repository.

multi-gitter

You can apply pinact to all repositories using multi-gitter.

Create the following files:

config.yaml
run.sh
main.sh

config.yaml:

e.g.

git-type: cmd
branch: pin-github-actions
skip-forks: true
org:
  - szksh-lab # Update with your organization
# repo:
#   - szksh-lab/test-1 # For test
labels:
  - pin-github-actions
pr-title: "ci: Pin versions of GitHub Actions to full commit hash"
pr-body: |
  ## What?

  This PR pins versions of GitHub Actions to full commit hash by pinact.
  In general, this PR doesn't change the behavior of the workflows, so you can merge this safely.

  ## Why?

  Last weekend, the popular GitHub Action tj-actions/changed-files action was compromised.

  - https://semgrep.dev/blog/2025/popular-github-action-tj-actionschanged-files-is-compromised/
  - https://www.stepsecurity.io/blog/harden-runner-detection-tj-actions-changed-files-action-is-compromised

  All tags were tampered and they pointed to a revision with malicious code.

  The issue was solved, but similar issues could happen again.
  To avoid this kind of issues, we should pin versions of GitHub Actions.
  This is a common practice of GitHub Actions.

  https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#using-third-party-actions

  > Pin actions to a full length commit SHA
  > Pinning an action to a full length commit SHA is currently the only way to use an action as an immutable release.
  > Pinning to a particular SHA helps mitigate the risk of a bad actor adding a backdoor to the action's repository, as they would need to generate a SHA-1 collision for a valid Git object payload.
  > When selecting a SHA, you should verify it is from the action's repository and not a repository fork.

  ## How was this pull request created?

  This pull request was created by [pinact](https://github.com/suzuki-shunsuke/pinact) and [multi-gitter](https://github.com/lindell/multi-gitter).

  ## Due Date

  Please merge this pull request by 2025-03-31.
  If it's difficult, please ask at the Slack channel #sre.

  ## Contact

  If you have any question, please ask at the Slack channel #sre.

run.sh:

#!/usr/bin/env bash

set -eu

export GITHUB_TOKEN=$(gh auth token)

multi-gitter run ./main.sh \
    --config config.yaml

main.sh:

#!/usr/bin/env bash

set -eu

pinact run

Make main.sh executable:

chmod +x main.sh

Before running it across all repositories, test it on one repository:

config.yaml:

# org:
#   - szksh-lab
repo:
  - szksh-lab/test-1 # Please fix

Run run.sh to create a pull request:

bash run.sh

Once confirmed, apply it to all repositories.

bash run.sh

Example Pull Request: https://github.com/szksh-lab/test-1/pull/23

For more details of multi-gitter, please see the multi-gitter repository.

Continuous Updates

You can update actions by Dependabot or Renovate.

Dependabot:

Renovate:

You can also run pinact in CI using pinact-action.

Conclusion

To improve security, you should pin GitHub Action versions to a full-length commit hash.
You can pin GitHub Actions across all repositories in your GitHub Organizations using pinact and multi-gitter.