pinactでGitHub ActionsのアクションをSHA固定する

サプライチェーン攻撃のリスクを下げるため、pinactを使ってGitHub ActionsのサードパーティアクションをコミットSHAで固定しました。そのときの作業内容をまとめています。

目次

はじめに

Trivyなどに対するサプライチェーン攻撃の発生をきっかけに、GitHub Actionsのワークフローを見直しました。 タグ指定のままになっているアクションがいくつか残っていたため、pinactを使ってコミットSHAに置き換えています。

本記事はそのときの作業内容の記録です。

タグ指定のリスク

GitHub Actionsのサードパーティアクションでは、READMEやサンプルコードでも actions/checkout@v6 のように指定する書き方が多く、そのまま使われている例も見かけます。 ただしこの方式には以下のリスクがあります。

  • メジャーバージョンを表す参照(v1 など)のみを指定している場合、不正なバージョンが新しく発行されると意図せず実行してしまう
  • タグは書き換え可能なため、攻撃者がタグを不正なコミットに差し替える余地がある

GitHub Actionsを介したサプライチェーン攻撃は、直近でも実際に発生しています。

例: Trivy Security incident 2026-03-19 conclusion

コミットSHAで指定すれば、実行されるコードは不変になります。 SHAで固定することで、不意に不正なコードが実行されるリスクを排除できます。

# Before: タグで指定
uses: actions/checkout@v6
# After: SHAで指定 (コメントでバージョンも併記するとわかりやすい)
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

対応手順

コミットSHAを都度調べるのは手間がかかるため、 pinact というツールを活用しました。

pinactのインストール

インストール方法は pinact公式のINSTALLドキュメント を参照してください。 今回はHomebrewでインストールしました。

brew install pinact

pinactの初期化

プロジェクトルートで以下のコマンドを実行します。

pinact init '.github/pinact.yaml'

pinactは .github 配下のワークフローファイルにのみ適用するため、設定ファイルもプロジェクトルートではなく .github/pinact.yaml に配置しました。 引数なしで pinact init を実行した場合は、プロジェクトルートに .pinact.yaml が作成されます。

SHA固定の実行

以下のコマンドで、GitHub ActionsのワークフローファイルをSHA固定の記述に書き換えました。

pinact run --min-age 7

--min-age 7 でリリースから7日未満のバージョンを除外しています。 サプライチェーン攻撃が検出されるまでの猶予期間を確保する意図です。

注意点

ブランチ指定のアクション

アクションの参照がブランチ名 (例: main) で指定されている場合、pinactはSHA解決に失敗してエラーになります。 この場合は対象アクションのリリースページを確認し、適切なバージョンタグに書き換えた上でpinactを実行します。

GitHub APIのレートリミット

pinactはGitHub APIを呼び出すため、一度に多くの変更を行うとAPIのレートリミットに引っかかることがあります。 今回の作業中にも一度発生しましたが、その際は時間を空けて再度実行することで解消しました。

GitHubのアクセストークンを使ってpinactを実行すれば、レートリミットを緩和することもできます。

今後の展望

今後はGitHub側でもアクションのSHA固定を支援する仕組みが提供される見込みです。

What’s coming to our GitHub Actions 2026 security roadmap - The GitHub Blog

公式の仕組みが整い次第、そちらに合わせて順次対応していきたいと考えています。