2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GitHubのReleasesでファイルを配る際のセキュリティ対策とその実践方法

2
Last updated at Posted at 2026-02-03

これは何?

先日こちらのツイートに影響を受け、自分の公開しているリポジトリのReleasesに対して改ざん対策を行った。

ツイートとツイートで引用されているリポジトリ12を参考にさせていただきつつ、自分でもいろいろ調べた結果をまとめた。

想定する読者

GitHubのReleaseページのセキュリティ対策を行いたい開発者
(見分ける方法は元ツイをご覧ください)


GitHubでReleaseする実行ファイルの改ざん防止が必要な背景

セキュリティ的な観点だけで言えば、ソースが公開されているソフトウェアに対しては

  • ソースをチェック
  • 自前でビルド3

すべきだとは思う。

しかし、自前でビルドするのは手間がかかるし、非エンジニアの方に使ってもらうハードルが高くなる等のデメリットもある。

そのため、筆者を含めGitHubリポジトリのReleasesページに配置されている実行ファイル(以後、artifactと記載)をダウンロードして使うこともあると思う。

この際に注意すべき点として、GitHubのReleasesページから悪意のある実行ファイルをダウンロードさせる攻撃4が存在していることだ

これには、

  • リポジトリのソース自体が汚染されてしまい、悪意のあるコードを含んだartifactが配布されてしまうケース
    • 2024年のXZ Utilsのように開発者に悪意があるケース5
    • アカウントが乗っ取られてしまうケース(本記事で紹介するコミットとtagに
  • artifactだけを改ざんするケース(本記事のメインの対象)

が考えられる。

そのため、Releasesページから後者の危険がないことを確認できるようにすることはユーザに安心して利用してもらう上で重要である。


紹介するGitHubリポジトリの設定概要

  • Release自体の方式変更 --> Release artifactの差し替え防止
    • Immutable Releasesを利用する
    • Releaseの作者をGitHub Actionsにする
  • 署名の付与 --> GitHub アカウント乗っ取り時の不正リリース防止
    • Release Tagに署名をうつ
    • commitに署名をうつ

これにより、

実施前イメージ6

image.png

実施後イメージ↓

image.png


Release方式変更

Immutable Releaseを利用する

リポジトリのSettings --> General --> Releases Enable relase immutabilityを有効にする

image.png

この設定をすることで

  • 一度作成したRelease tagは特定のcommitにロックされるため、変更/削除負荷
  • Releaseに載せるアセットの変更や削除不可
  • Release attestationsファイルが自動作成される7

と、artifactが改ざんに強い状態になる。


Releaseの作成者をGitHub Actionsにする

Immutable Release単体ではartifactが差し替えられていないことしか保証できない。
そのため、少なくとも Release時点でのリポジトリ状態に基づいてビルドされたartifactであることが分かる。

release tagを手動で作り、これをトリガーにGitHub Actionsを実行してartifactを自動アップロードする形から、

release.yaml.prev
name: Release

on:
  release:
    types: [created]


jobs:
  build-and-release:
    runs-on: ubuntu-latest

    permissions:
      contents: write

    steps:
      - name: Checkout code
        uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0

      - name: Make build script executable
        run: chmod +x ./build.sh

      - name: Build JAR file
        run: ./build.sh

      - name: Create Release
        uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15
        with:
          files: ./build/airis-burp.jar
          generate_release_notes: true
          draft: false
          prerelease: false

release tagのpushをローカルから実行し、これをトリガーにしてRelease自体もGitHub Actionsで作成する形に変更した。

release.yaml
name: Release

on:
  push:
    tags:
      - 'v*'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1

      - run: chmod +x ./build.sh
      - run: ./build.sh

      - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
        with:
          name: jar
          path: build/airis-burp.jar

  release:
    needs: build
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v4
      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
        with:
          name: jar
          path: build

      - run: gh release create "$GITHUB_REF_NAME" build/airis-burp.jar
        env:
          GH_TOKEN: ${{ github.token }}

softprops/actions-gh-releaseを使うと以下のようなエラーが発生した。
softpropsが先にreleaseを作ってしまい、これがimmutableのため変更できないのが原因だったため、直接gh release create2したところうまくいった。

Error: Failed to upload release asset airis-burp.jar. received status code 422 Cannot upload assets to an immutable release. undefined

署名の付与

commitやtagの署名は、GitHub の UI 上の表示ではなく、対応する秘密鍵を保持している主体が実際にそのcommitやtagを作成したことを保証する。
そのため、GitHub アカウントが乗っ取られても秘密鍵が漏洩していなければ、署名付きの不正なリリースは作成できない。

SSHの秘密鍵と公開鍵を作成

Release tagとcommitに署名をつける手順はまとめて実施した。

既存のGitHubログイン用のSSH鍵を使いまわすことも考えたが、セキュリティの権限分離の観点から再作成することにした。
ちゃんとやるなら、YubiKeyのような物理鍵を使ったり、GPGを使うほうが良いかもしれない。

ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_signing -C "git-signing"

公開鍵をGitHubに登録する

GitHubの個人設定からAccess --> SSH and GPG keysから追加できる。

GitHubのUIが個人的にわかりにくかったので注意。

ログイン用の鍵を登録するボタンと同じボタンを押下し、Key typeを切り替えてSignning Keyを選ぶ。

image.png

git configの設定

  • ssh鍵を使って署名を作成すること
  • 使う公開鍵のPATH
  • commitに署名をつけること
  • tagに署名をつけること

を設定に追加した。

git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519_signing.pub
git config --global commit.gpgsign true
git config --global tag.gpgsign true

これだけだとうまくいかなかったのだが、~/.config/git/配下に信頼する鍵を記載したファイルを作成し、このPathをgit configで設定したらうまく行った。

mkdir -p ~/.config/git
touch ~/.config/git/allowed_signers
cat ~/.config/git/allowed_signers
GitHubのユーザ名 ssh-ed25519 公開鍵....

git config --global gpg.ssh.allowedSignersFile ~/.config/git/allowed_signers
# tagに署名がついたかチェック
git tag -a v0.1.8 -m "release v0.1.8"
git push origin v0.1.8
gh release verify v0.1.8
Resolved tag v0.1.8 to sha1:11c52920eebb3d411e9b62eeb4b5d199bd97c001
Loaded attestation from GitHub API
✓ Release v0.1.8 verified!

Assets
NAME            DIGEST                                                          
airis-burp.jar  sha256:0257e3d2c434595b5ee1231ce5afe9ce26bc94902d301991f87eb6...

# 署名設定前のRelease tag
gh release verify v0.1.0
no attestations for tag v0.1.0 (sha1:a2dda180acd89b64b5198bd947696c9852355198)
# commitに署名がついたか確認
commit c3c0fad9548596f990291f26d8bf5d4eeab5fda5
Good "git" signature for sigma with ED25519 key SHA256:xxxxxxxxxxxxxxxxxx
Author: sigma
Date:   Mon Feb 2 23:28:55 2026 +0900

    chore: fix release.yml


# 署名をつける前のcommit
git log --show-signature
commit 57036f7504156934612148e1bd4c2718a2eee7ec
Author: sigma
Date:   Thu Aug 28 20:06:11 2025 +0900

    first commit

一応Webからの見え方も再掲

image.png


おまけ: ビルドの再現性を高めるためのNix Flake

今回実験台に利用したリポジトリはDockerを使ってビルドしているので、Nix Flakeを使ってビルドしたほうがビルドの再現性が担保されるのでより良いと思う。

HaskellとDenoの一部のみにしかNix Flake導入できてないので本記事ではこれ以上触れないがみんなNix Flake使っていこうぜ!


Reference

  1. https://github.com/suzuki-shunsuke/ghir

  2. https://github.com/suzuki-shunsuke/go-release-workflow 2

  3. https://www.reddit.com/r/Scams/comments/1b8ckap/cryto_developer_metamask_scam/ 偽のリクルータ経由で誘導されたリポジトリをclone & runしたら情報抜かれた話もあるので、リポジトリ自体が怪しくないかを確認すべし

  4. https://www.trendmicro.com/ja_jp/research/25/b/lumma-stealers-github-based-delivery-via-mdr.html

  5. https://ja.wikipedia.org/wiki/XZ_Utils%E3%81%AE%E3%83%90%E3%83%83%E3%82%AF%E3%83%89%E3%82%A2

  6. commitに署名がついているのはgh prを使って操作したmerge commitが署名されているだけで開発時のcommitには署名は付与されていなかった。

  7. https://github.blog/changelog/2025-10-28-immutable-releases-are-now-generally-available/

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?