はじめに
2026年5月、マネーフォワードがGitHub認証情報の不正アクセスを発表しました。流出したとされる情報には、ソースコード一式のほか、カード保持者370件の氏名・カード番号下4桁、そしてソースコードにハードコードされた各種認証キー・パスワードが含まれていました。
この事件の詳細な分析は こちらの記事 にまとめられており、シークレットがリポジトリに混入する主な経路として、以下が挙げられています。
-
.envファイルを.gitignoreに入れ忘れた誤コミット - CI/テストのフィクスチャに本番データを流用
- バグ調査時のダンプファイルが削除されず残存
- マイグレーションスクリプトへの直接埋め込み
Git履歴は特に注意が必要です。ファイルを削除しても、過去のコミット履歴には残り続けます。攻撃者が git log -p を実行するだけで、すべての履歴から認証情報を抽出できてしまいます。
では、コミットからpushまでの各フェーズで、どうすればシークレット混入を防げるのか?
本記事では、pre-commit(コミット前の早期検知)・CI(マージの門番)・Global Server Hooks(pushそのものをブロックする最終防衛ライン)の3層防御を Gitleaks で構築する手順を、安全なインストール方法とともに解説します。
安全なインストール手順
curl | bash を使ってはいけない理由
ツールのインストール手順として、次のような形式をよく見かけます。
# ❌ やってはいけない例
curl https://example.com/install.sh | bash
これは非常に危険です。理由は以下のとおりです。
- 内容を確認せずに実行している — ダウンロードとシェル実行が同時に行われるため、スクリプトの中身を人間が確認できません。
- 改ざんに気づけない — 配信サーバーやCDNが侵害されていた場合、悪意あるスクリプトがそのまま実行されます。
- サプライチェーン攻撃の入口になる — セキュリティツール自身がマルウェアの配布経路になった事例は実際に存在します。
セキュリティツールこそ、インストール方法を慎重に選ぶ必要があります。
前提
- Git がインストールされていること
- Python 3.8以上がインストールされていること(pre-commit に必要)
- Linux / macOS 環境を想定(Windowsはパス等を適宜読み替えてください)
Step 1. Gitleaks をバージョン固定でインストール
公式の GitHub Releases からバイナリを直接取得します。バージョンを固定することで、予期しないアップデートによる挙動変化を防げます。
# バージョンを変数で管理する
GITLEAKS_VERSION="v8.24.3"
# ダウンロード(実行前にURLを確認してください)
curl -sSLO \
"https://github.com/gitleaks/gitleaks/releases/download/${GITLEAKS_VERSION}/gitleaks_8.24.3_linux_x64.tar.gz"
ダウンロード後、必ずチェックサムを検証してから展開してください。
# チェックサムファイルも取得する
curl -sSLO \
"https://github.com/gitleaks/gitleaks/releases/download/${GITLEAKS_VERSION}/checksums.txt"
# チェックサム検証
sha256sum --check --ignore-missing checksums.txt
問題がなければ展開してインストールします。
tar xzf gitleaks_8.24.3_linux_x64.tar.gz
sudo mv gitleaks /usr/local/bin/gitleaks
sudo chmod +x /usr/local/bin/gitleaks
# 動作確認
gitleaks version
企業環境では、公式バイナリを自社の内部レジストリにミラーして管理することをお勧めします。
Step 2. pre-commit をインストール
pip install pre-commit
# インストール確認
pre-commit --version
Step 3. .pre-commit-config.yaml を作成
リポジトリのルートに以下のファイルを作成します。
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.24.3 # バージョンは固定する
hooks:
- id: gitleaks
rev はバージョンを固定してください。latest や main など可変なものは、意図しない変更が混入するリスクがあります。
Step 4. hook をインストール
pre-commit install
これで、git commit を実行するたびに Gitleaks がステージングされた差分を自動でスキャンします。
Step 5. 動作確認
全ファイルを対象にスキャンして、既存の混入がないかを確認します。
pre-commit run gitleaks --all-files
問題がなければ以下のように表示されます。
gitleaks...............................................................Passed
Step 6. (オプション)カスタムルールの設定
プロジェクト固有の機密情報パターンや、テスト用ダミー値の除外(allowlist)が必要な場合は、.gitleaks.toml を作成します。
[extend]
useDefault = true
[[rules]]
id = "custom-internal-token"
description = "社内独自トークン"
regex = '''MYAPP_[A-Z0-9]{32}'''
tags = ["token", "custom"]
[allowlist]
description = "テスト用ダミー値を除外"
regexes = [
'''EXAMPLE_KEY_FOR_TESTING''',
]
pre-commit だけでは足りない理由
pre-commit は強力ですが、開発者がスキップできます。
# スキップの例(組織内での悪用に注意)
SKIP=gitleaks git commit -m "fix"
また、リポジトリを clone した開発者が pre-commit install を実行しなければ、hook 自体が動きません。
CI にも同じチェックを入れる
GitLab CI の場合は以下のように設定します。
# .gitlab-ci.yml
gitleaks:
image: zricethezav/gitleaks:v8.24.3 # latestは使わない
script:
- gitleaks detect --source . --verbose --log-opts="--all"
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
latest タグを避ける理由は3つあります。
-
再現性が失われる —
latestは CI 実行のたびに異なるバージョンのイメージを引く可能性があります。「昨日は通ったのに今日は落ちる」という原因不明の挙動変化につながります。 - ルール変更による誤検知・見逃し — Gitleaks はバージョンアップのたびに検知ルールセットが更新されます。バージョンを固定しないと、ルール追加による突然の誤検知や、ルール変更による見逃しが発生しうる状態になります。
-
サプライチェーンリスク — Docker Hub のイメージは
latestタグが上書き可能なため、万一レジストリ側が侵害された場合に悪意あるイメージが流れ込むリスクがあります。インストール手順でcurl | bashを避けた理由と同じ構造です。
ただし、push 時点でブロックするには CI では間に合いません。 CI はあくまで「main へのマージを防ぐ」層です。push そのものをブロックするには、後述する GitLab の Global Server Hooks が必要です。
push そのものをブロックする — Global Server Hooks
pre-commit も CI も、「開発者のローカル」または「マージ前」での検知です。push が GitLab サーバーに届いた時点で、すでにシークレットはリモートリポジトリに存在しています。
push を受け付ける前にブロックするには、GitLab Self-Managed の Global Server Hooks を使います。
公式ドキュメント: Server hooks | GitLab
Global Server Hooks は、GitLab サーバー上の特定ディレクトリにスクリプトを置くだけで、全リポジトリへの push に自動適用されます。Push Rules(GitLab UI で設定できる正規表現ブロック)と異なり、Gitleaks のような外部ツールを呼び出せるため、より高精度な検知が可能です。
設定ディレクトリ(Omnibus インストールの場合)
/var/opt/gitlab/gitaly/custom_hooks/pre-receive.d/
このディレクトリ配下に置いたスクリプトが、ファイル名のアルファベット順にすべての push に対して実行されます。
スクリプト例
#!/bin/bash
# /var/opt/gitlab/gitaly/custom_hooks/pre-receive.d/gitleaks.sh
while read oldrev newrev refname; do
if [ "$oldrev" = "0000000000000000000000000000000000000000" ]; then
range="$newrev"
else
range="$oldrev..$newrev"
fi
# 差分のみスキャン(全履歴スキャンは性能影響が大きいため避ける)
git rev-list "$range" | while read commit; do
git diff-tree --no-commit-id -p "$commit" | \
gitleaks detect --pipe --no-git -v
if [ $? -ne 0 ]; then
echo "❌ 機密情報が検出されました。push をブロックします。"
exit 1
fi
done
done
# 実行権限を付与する
chmod +x /var/opt/gitlab/gitaly/custom_hooks/pre-receive.d/gitleaks.sh
注意点
Global Server Hooks にはいくつかの制約があります。
- タイムアウト制限がある — push 処理全体が長引くと push が失敗します。全履歴スキャンは避け、差分のみを対象にしてください。
- Geo 環境ではセカンダリに複製されない — Geo レプリカを使っている場合、セカンダリノードには別途手動で配置が必要です。
- Praefect クラスタでは全 Gitaly ノードへの配置が必要 — HA 構成の場合、すべてのノードにスクリプトを配置してください。
- 設定はサーバー管理者のみ — GitLab の UI からは操作できません。
役割分担のまとめ
| 層 | 手段 | 強制力 | 対象 |
|---|---|---|---|
| コミット前(ローカル) | pre-commit + Gitleaks | △ スキップ可能 | 個人の手元 |
| push 時 | Global Server Hooks | ✅ サーバー側でブロック | 全リポジトリ |
| MR マージ前 | GitLab CI + Gitleaks | ✅ マージをブロック | main への混入防止 |
pre-commit は開発者体験を高める「早期検知」、CI は「マージの門番」、Global Server Hooks は「push そのものを止める最終防衛ライン」という役割分担で考えると整理しやすくなります。
まとめ
「混入してから対処する」ではなく、「混入させない仕組みを先に作る」ことが組織全体のセキュリティ水準を高める第一歩です。まず pre-commit を導入して開発者の手元での早期検知を習慣化し、次に CI・Global Server Hooks を加えてチーム全体の防御を固める、という順で段階的に整備することをお勧めします。
Gitleaks のインストールにあたっては、curl | bash を避け、バージョン固定とチェックサム検証を徹底してください。セキュリティツール自体がサプライチェーン攻撃の入口にならないよう、取得元の検証も重要です。
マネーフォワードの事件は、認証情報の管理とシークレットスキャンの重要性を改めて示しています。