メインコンテンツへスキップ
← 記事一覧に戻る

個人開発で秘密鍵をgit pushしかけた話 — 二度と事故を起こさない仕組みの作り方

6 min readセキュリティ
#Git#セキュリティ#個人開発#GitHub

git pushした後に冷や汗をかいたことはありませんか?

結論から言います。.gitignoreだけでは秘密情報の漏洩は防げません。 pre-commitフックを入れれば、うっかりミスを物理的に不可能にできます。設定は3分で終わります。

この記事では、筆者が実際にセッションCookieをpushしかけた体験と、その後に構築した「二度と事故が起きない仕組み」を全部公開します。

💡

の体験談

筆者はClaude Crewという11体のAIエージェントを運用しています。そのsns-automationリポジトリで、noteのセッションCookie(.note-auth/state.json)がgit statusに表示されているのを発見しました。pushする直前でした。


何が起きたか

AIエージェントの1つが、noteへの自動投稿のためにブラウザ認証の状態(セッションCookie)をJSONファイルに保存していました。

.note-auth/
  state.json  ← noteのセッションCookie・認証トークンが平文で入っている

このファイルが .gitignore に登録されておらず、git status で untracked file として表示されていたのです。

もしこのままpushしていたら:

  • noteアカウントの乗っ取りリスク
  • セッションCookieでログイン済みの操作が第三者に可能に
  • GitHubのコミット履歴に残るため、force pushしても完全削除が困難

なぜ.gitignoreだけでは不十分なのか

.gitignore は「知っているファイル」しか除外できません。

シナリオ.gitignoreで防げるか
.env ファイル○(事前に書いてあれば)
新しく生成された認証statex(パターンを知らない)
ダウンロードしたService AccountのJSONキーx
ライブラリが勝手に生成した一時ファイルx

つまり、「まだ知らないファイル」に対しては無力です。


解決策①: .gitignoreを網羅的にする

まず .gitignore を「考えられる秘密ファイルを全パターン」カバーするように強化します。

# Environment
.env
.env.local
.env.*

# Auth state / credentials (NEVER commit)
.note-auth/
*.pem
*.key
*.p12
*.pfx
*-credentials.json
*-service-account.json
service-account*.json
client_secret*.json
oauth2*.json
token.json
credentials.json

# Cookies
*_cookies.json

# Google Cloud
gcloud/
.gcp/

ポイント: ワイルドカードを積極的に使う。service-account*.json のように、ファイル名のパターンで網をかけます。


解決策②: pre-commitフックで自動検出(本命)

これが本命です。コミット時に秘密情報パターンを自動検出し、コミット自体を止めます。

.git/hooks/pre-commit に以下を保存してください:

#!/bin/bash
# Pre-commit hook: 秘密情報を含むファイルのコミットをブロック

RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'

BLOCKED=0
FILES=$(git diff --cached --name-only --diff-filter=ACM)

if [ -z "$FILES" ]; then
  exit 0
fi

# 1. 危険なファイル名パターン
DANGEROUS_PATTERNS=(
  "\.pem$"
  "\.key$"
  "\.p12$"
  "credentials\.json"
  "service.account.*\.json"
  "client_secret.*\.json"
  "token\.json"
  "state\.json"
  "_cookies\.json"
  "\.env$"
  "\.env\."
)

for FILE in $FILES; do
  for PATTERN in "${DANGEROUS_PATTERNS[@]}"; do
    if echo "$FILE" | grep -qE "$PATTERN"; then
      echo -e "${RED}BLOCKED${NC}: $FILE (dangerous filename: $PATTERN)"
      BLOCKED=1
    fi
  done
done

# 2. ファイル内容に秘密情報パターンがないか
SECRET_PATTERNS=(
  "PRIVATE KEY"
  "BEGIN.*KEY"
  "sk_live_"
  "sk_test_"
  "ghp_[a-zA-Z0-9]{36}"
  "\"_note_session"
  "\"type\":.*\"service_account\""
)

for FILE in $FILES; do
  if [ ! -f "$FILE" ]; then continue; fi
  if file "$FILE" 2>/dev/null | grep -q "binary"; then continue; fi

  for PATTERN in "${SECRET_PATTERNS[@]}"; do
    if git diff --cached -- "$FILE" | grep -qE "$PATTERN"; then
      echo -e "${RED}BLOCKED${NC}: $FILE contains secret pattern: $PATTERN"
      BLOCKED=1
      break
    fi
  done
done

if [ $BLOCKED -ne 0 ]; then
  echo ""
  echo -e "${YELLOW}コミットをブロックしました。秘密情報が含まれている可能性があります。${NC}"
  echo "本当にコミットする場合は: git commit --no-verify"
  exit 1
fi

exit 0

保存したら実行権限を付けます:

chmod +x .git/hooks/pre-commit

動作確認

試しにStripeのテスト秘密鍵を含むファイルをコミットしてみます:

echo 'sk_live_fake1234567890abcdef' > test-leak.txt
git add test-leak.txt
git commit -m "test"

結果:

BLOCKED: test-leak.txt contains secret pattern: sk_live_

コミットをブロックしました。秘密情報が含まれている可能性があります。
本当にコミットする場合は: git commit --no-verify

コミットが止まりました。 事故防止成功です。


解決策③: GitHub Secret Scanning(補足)

GitHubにはpush時に秘密情報を検出する「Secret Scanning」機能があります。

  • パブリックリポジトリ: 無料で自動有効
  • プライベートリポジトリ: GitHub Advanced Security(有料)が必要

個人開発者はプライベートリポジトリが多いので、pre-commitフックの方が現実的です。


まとめ

対策効果設定時間
.gitignore強化既知のパターンをブロック1分
pre-commitフック未知のパターンも検出・コミット拒否2分
GitHub Secret Scanningpush時の最終防衛(パブリックのみ無料)0分

.gitignore + pre-commitフックの2段構えが最強です。 3分で設定できるので、今すぐやりましょう。

← 記事一覧に戻る