はじめに:まず深呼吸しよう

「やってしまった」 — GitHubリポジトリの設定を変更していて、気づいたら1分間publicになっていた。

心臓がバクバクして、「全部漏れた」「クレデンシャル悪用される」「会社に報告しなきゃ」と頭の中がパニックになっていませんか?

結論から言います:1分間の公開で即座に壊滅的な被害が出る可能性は、実際にはかなり低いです。

ただし「低い」と「ゼロ」は違います。この記事では、過度に恐れず、かつ必要な対策を確実に行うための 実践的なガイド を提供します。


この記事の対象読者

  • 「やっちゃったかも…」と今まさに不安な方
  • セキュリティインシデント対応の手順を知りたいエンジニア
  • 「本当に危険なの?」を冷静に判断したい方
  • 予防策を事前に知っておきたい方

1. まず理解する:1分間の公開で何が起きうるか

1.1 現実的なリスク評価

1分間のpublic公開で起きる可能性

リスクレベル 内容 詳細
🟢 起きやすい クローラー/ボットによる自動検出 GitHubを常時監視するボットは存在する
🟢 起きやすい GitHub検索インデックスへの追加 公開されると検索対象になる可能性
🟡 確率は低い 悪意ある人間がたまたま発見 1億以上のリポジトリから見つかる確率は低い
🟡 確率は低い 自動スキャナーがシークレットを検出 GitHub Secret Scanningが動作する可能性
🔴 起きにくい 標的型攻撃による狙い撃ち 1分では現実的に不可能
🔴 起きにくい 大規模なデータ窃取 発見→分析→窃取には時間が必要

1.2 GitHub Secret Scanningの存在

知っておくべき事実:GitHubには Secret Scanning という機能があり、publicリポジトリで検出されたシークレットは 自動的にプロバイダーに通知 されます。

プロバイダー 自動通知 自動無効化
AWS ✅ (一部)
Google Cloud
Azure
Slack
npm
PyPI

つまり、1分でも公開された場合、GitHubが検知してプロバイダーに通知している可能性があります。これは「守ってくれている」という意味では良いニュースですが、「検知された=漏洩した」という証拠にもなります。


2. インシデント発生から対応完了までの流れ

以下のフローチャートに従って、落ち着いて対応してください。

    flowchart TD
    A[🚨 public設定に気づいた] --> B{今もpublicか?}
    B -->|はい| C[即座にprivateに戻す]
    B -->|いいえ| D[公開期間を確認]
    C --> D

    D --> E{シークレットが<br>含まれていたか?}

    E -->|不明| F[git履歴全体を検索]
    E -->|いいえ| G[✅ 低リスク<br>ログ記録のみで完了]
    E -->|はい| H{どの種類の<br>シークレット?}

    F --> E

    H -->|APIキー/トークン| I[🔴 即座にローテーション]
    H -->|パスワード| J[🔴 即座に変更]
    H -->|SSH鍵| K[🔴 新規生成・旧鍵削除]
    H -->|個人情報| L[🟡 法務/コンプライアンス相談]

    I --> M[影響範囲の確認]
    J --> M
    K --> M
    L --> M

    M --> N{不正利用の<br>痕跡があるか?}

    N -->|はい| O[🔴 インシデント対応<br>エスカレーション]
    N -->|いいえ| P[📝 記録・報告書作成]
    N -->|確認できない| P

    P --> Q[✅ 予防策の導入]
    O --> Q

    Q --> R[完了]

    style A fill:#ff6b6b,color:#fff
    style C fill:#ff6b6b,color:#fff
    style I fill:#ff6b6b,color:#fff
    style J fill:#ff6b6b,color:#fff
    style K fill:#ff6b6b,color:#fff
    style O fill:#ff6b6b,color:#fff
    style G fill:#51cf66,color:#fff
    style R fill:#51cf66,color:#fff
    style L fill:#ffd43b,color:#000
  

3. 【チェックリスト】今すぐやるべきこと

Phase 1: 初動対応(最初の5分)

    ## 初動チェックリスト

### 即座に実行
- [ ] リポジトリをprivateに戻したか確認
- [ ] 公開されていた正確な時間を記録(Settings > Danger Zone の変更履歴)
- [ ] 自分以外にアクセスした形跡がないか確認(Insights > Traffic)

### 状況の把握
- [ ] 公開期間: ____分間(__:__ 〜 __:__)
- [ ] リポジトリ名: ____________________
- [ ] 含まれていた可能性のある機密情報:
  - [ ] APIキー / トークン
  - [ ] パスワード / 認証情報
  - [ ] SSH秘密鍵
  - [ ] 環境変数ファイル(.env)
  - [ ] 個人情報(PII)
  - [ ] 社内ドキュメント
  - [ ] 上記いずれも含まれていない
  

Phase 2: シークレットの検索(5〜15分)

    # リポジトリ内のシークレットを検索するコマンド

# 1. .envファイルの存在確認
find . -name ".env*" -o -name "*.env" 2>/dev/null

# 2. 一般的なシークレットパターンの検索
grep -rE "(api[_-]?key|secret|password|token|credential)" \
  --include="*.{js,ts,py,rb,go,java,yaml,yml,json,xml,conf,config}" \
  . 2>/dev/null | head -50

# 3. AWS認証情報の検索
grep -rE "AKIA[0-9A-Z]{16}" . 2>/dev/null

# 4. 秘密鍵の検索
grep -rE "-----BEGIN (RSA |DSA |EC |OPENSSH )?PRIVATE KEY-----" . 2>/dev/null

# 5. git履歴全体での検索(過去のコミットも含む)
git log -p --all -S "password" -- "*.py" "*.js" "*.ts" | head -100
  

推奨ツール:自動スキャン

    # truffleHog(git履歴全体をスキャン)
trufflehog git file://. --only-verified

# gitleaks(高速なシークレット検出)
gitleaks detect --source . --verbose

# git-secrets(AWSに特化)
git secrets --scan
  

Phase 3: シークレットのローテーション(15分〜)

重要: シークレットが含まれていた場合は、無条件でローテーションしてください。 「たぶん大丈夫」は通用しません。

    ## ローテーション・チェックリスト

### クラウドプロバイダー
- [ ] AWS Access Key → IAMコンソールで新規作成、旧キー削除
- [ ] GCP Service Account Key → 新規JSON生成、旧キー削除
- [ ] Azure Service Principal → シークレット再生成

### SaaS / API
- [ ] Slack Bot Token → アプリ設定で再生成
- [ ] GitHub Personal Access Token → 新規作成、旧トークン削除
- [ ] Stripe API Key → ダッシュボードでロールまたは再生成
- [ ] SendGrid / Mailgun → API Key再生成

### データベース
- [ ] 本番DBパスワード → 変更後、アプリ側も更新
- [ ] Redis / ElastiCache → AUTH設定更新

### インフラ
- [ ] SSH秘密鍵 → `ssh-keygen` で新規生成、authorized_keysを更新
- [ ] SSL/TLS証明書 → 秘密鍵が漏洩していれば再発行
  

4. 「本当に漏洩したか」を判断するフローチャート

1分間の公開で「実際に誰かに見られたか」を判断するのは難しいですが、以下の指標が参考になります。

    flowchart TD
    A[漏洩の可能性を評価] --> B{GitHub Secret Scanning<br>からアラートが来た?}

    B -->|はい| C[🔴 GitHubが検知<br>= プロバイダーに通知済み]
    B -->|いいえ| D{Traffic Insightsで<br>異常なアクセスがある?}

    C --> E[該当シークレットは<br>確実にローテーション]

    D -->|はい| F[🟡 人間またはボットが<br>アクセスした可能性]
    D -->|いいえ| G{公開中にGitHub検索に<br>インデックスされた?}

    F --> E

    G -->|はい| H[🟡 検索経由で発見<br>された可能性あり]
    G -->|いいえ| I{クラウドプロバイダーから<br>不正利用アラートが来た?}

    H --> E

    I -->|はい| J[🔴 実際に悪用された<br>緊急対応が必要]
    I -->|いいえ| K[🟢 現時点で悪用の<br>証拠なし]

    J --> L[インシデント対応チーム<br>エスカレーション]
    K --> M[予防的にローテーション<br>推奨]

    E --> N[監視を強化して経過観察]
    M --> N
    L --> N

    style C fill:#ff6b6b,color:#fff
    style J fill:#ff6b6b,color:#fff
    style F fill:#ffd43b,color:#000
    style H fill:#ffd43b,color:#000
    style K fill:#51cf66,color:#fff
  

確認方法

    # 1. GitHub Secret Scanningアラートの確認
# リポジトリ > Security > Secret scanning alerts

# 2. Traffic Insightsの確認
# リポジトリ > Insights > Traffic
# - Clones数が異常に多くないか
# - Unique visitorsに見知らぬ数がないか

# 3. AWSの場合:CloudTrailでAPIコール確認
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=AccessKeyId,AttributeValue=AKIA... \
  --start-time 2024-01-01T00:00:00Z

# 4. GCPの場合:監査ログ確認
gcloud logging read "protoPayload.authenticationInfo.principalEmail:*" \
  --project=YOUR_PROJECT --limit=50
  

5. 冷静に考える:1分間で何ができるか

攻撃者の視点

アクション 1分で可能か 現実的な確率
GitHub検索で発見 ❌ インデックスに時間がかかる 極めて低い
自動クローラーが検出 ⚠️ 運が悪ければ 低い
手動でリポジトリ発見 ⚠️ 偶然のアクセス 極めて低い
シークレットを抽出 ✅ 発見されれば可能 発見された場合は高い
シークレットを悪用 ⚠️ 自動化されていれば 中程度
データを全部ダウンロード ✅ git cloneは高速 発見された場合は高い

ポイント: 「発見される」確率は低いが、「発見されたら」その後は速い。 だからこそ、予防的なローテーションが重要です。

実際の統計(参考)

  • GitHubには1億以上のリポジトリが存在
  • 1分間で「あなたの」リポジトリが発見される確率は天文学的に低い
  • ただし、シークレットスキャナーは24時間稼働している
  • 公開リポジトリは定期的にスキャンされている

6. 報告書テンプレート

会社やチームへの報告が必要な場合、以下のテンプレートを使用してください。

    # セキュリティインシデント報告書

## 概要
- **発生日時**: 2024年XX月XX日 HH:MM 〜 HH:MM(約X分間)
- **対象リポジトリ**: organization/repository-name
- **発見者**: [自分の名前]
- **報告日**: 2024年XX月XX日

## インシデント内容
GitHubリポジトリの可視性設定を誤ってprivateからpublicに変更し、
約X分間、インターネット上から閲覧可能な状態となった。

## 影響範囲
### 含まれていた可能性のある機密情報
- [ ] APIキー・トークン: [あり/なし/確認中]
- [ ] 認証情報: [あり/なし/確認中]
- [ ] 個人情報: [あり/なし/確認中]
- [ ] ソースコード: [あり]

### 漏洩の証拠
- GitHub Secret Scanningアラート: [あり/なし]
- Traffic Insights異常: [あり/なし]
- クラウドプロバイダーアラート: [あり/なし]

## 実施した対応
1. [HH:MM] リポジトリをprivateに変更
2. [HH:MM] シークレットの有無を確認
3. [HH:MM] 該当シークレットをローテーション
4. [HH:MM] 監視強化を設定

## ローテーションしたシークレット
| 種類 | 対象 | 完了日時 |
|-----|------|---------|
| AWS Access Key | AKIA... | HH:MM |
| GitHub Token | ghp_... | HH:MM |

## 再発防止策
1. [ ] pre-commitフックでシークレット検出を導入
2. [ ] リポジトリ設定変更時の承認フローを追加
3. [ ] 定期的なシークレットスキャンを自動化

## 結論
現時点で悪用された証拠は[確認されていない/確認された]。
予防的措置として全ての潜在的シークレットをローテーション済み。
継続的な監視を行い、異常があれば追加報告する。
  

7. 【最重要】.gitignoreしても過去のコミットに残っている問題

これが 最も見落としやすく、最も危険な罠 です。

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

    flowchart TD
    A[最初のコミット] -->|.envを含めてコミット| B[履歴に.envが残る]
    B --> C[後から.gitignoreに追加]
    C --> D[新規コミットには含まれない]
    D --> E[でも過去の履歴には残ったまま]

    E --> F[リポジトリをpublic化]
    F --> G[🔴 過去のコミットから<br>.envが丸見え]

    style A fill:#ff6b6b,color:#fff
    style B fill:#ff6b6b,color:#fff
    style G fill:#ff6b6b,color:#fff
    style C fill:#ffd43b,color:#000
    style D fill:#51cf66,color:#fff
  

よくある勘違い:

  • ❌ 「.gitignoreに追加したから大丈夫」
  • ❌ 「今の状態では見えないから安全」
  • ❌ 「ファイルを削除したから問題ない」

現実:

  • ✅ git履歴には全てのコミットが残っている
  • git log -p で過去の全変更が見える
  • ✅ publicになった瞬間、全履歴が公開される

7.2 自分のリポジトリをチェックする方法

    # 過去の全コミットで.envファイルを検索
git log --all --full-history -- "**/.env*"

# 過去の全コミットでシークレットっぽい文字列を検索
git log -p --all -S "password" | head -100
git log -p --all -S "api_key" | head -100
git log -p --all -S "secret" | head -100

# AWS認証情報が過去に含まれていたか
git log -p --all | grep -E "AKIA[0-9A-Z]{16}" | head -20

# 特定ファイルの履歴を確認
git log -p --all -- "**/credentials*"
git log -p --all -- "**/*.pem"
  

推奨: gitleaksで全履歴スキャン

    # インストール
brew install gitleaks  # macOS
# または
go install github.com/gitleaks/gitleaks/v8@latest

# 全履歴をスキャン(これが最も確実)
gitleaks detect --source . --verbose --log-opts="--all"
  

7.3 過去のコミットから削除する方法

注意: この操作は履歴を書き換えるため、force pushが必要になります。

方法1: BFG Repo-Cleaner(推奨・高速)

    # BFGをダウンロード
# https://rtyley.github.io/bfg-repo-cleaner/

# .envファイルを全履歴から削除
java -jar bfg.jar --delete-files .env

# 特定の文字列を全履歴から置換
java -jar bfg.jar --replace-text passwords.txt

# passwords.txt の中身例:
# AKIAIOSFODNN7EXAMPLE==>***REMOVED***
# my-secret-password==>***REMOVED***

# クリーンアップ
git reflog expire --expire=now --all
git gc --prune=now --aggressive

# force push(⚠️ 他のクローンに影響)
git push --force
  

方法2: git filter-repo(公式推奨)

    # インストール
pip install git-filter-repo

# 特定ファイルを全履歴から削除
git filter-repo --path .env --invert-paths

# 特定パターンにマッチするファイルを削除
git filter-repo --path-glob '*.pem' --invert-paths
  

7.4 履歴削除の現実的な判断

履歴削除すべきか?判断フロー

質問 YES NO
シークレットをローテーション済み? 履歴削除は必須ではない(旧情報は無効) まずローテーションを優先!
すでにpublicで公開されていた? 履歴削除してもclone済みコピーは残る → ローテーションが唯一の対策 履歴削除は有効な予防策
監査・コンプライアンス要件がある? 履歴削除を実施 ローテーション済みなら任意

重要: 履歴削除は「やらないよりマシ」だが、ローテーションの代わりにはならない。 すでに公開されていた場合、誰かが clone していれば履歴削除は無意味。

7.5 今後の予防策

    # 1. コミット前に必ずスキャン
gitleaks protect --staged

# 2. pre-commitフックで自動チェック
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.18.0
    hooks:
      - id: gitleaks

# 3. 新規リポジトリ作成時に最初から.gitignoreを設定
# (後から追加しても履歴には残る)
  

8. 二度と起こさないための予防策

8.1 シークレットをリポジトリに入れない

    # .gitignoreに追加すべき項目(最初のコミット前に!)
.env
.env.*
*.pem
*.key
credentials.json
serviceaccount.json
*secret*
  
    # git-secretsの導入(コミット前にブロック)
brew install git-secrets  # macOS
git secrets --install
git secrets --register-aws
  

8.2 pre-commitフックの導入

    # .pre-commit-config.yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.18.0
    hooks:
      - id: gitleaks

  - repo: https://github.com/awslabs/git-secrets
    rev: master
    hooks:
      - id: git-secrets
  

8.3 GitHub設定の強化

    ## GitHub設定チェックリスト

### Organization設定(管理者向け)
- [ ] リポジトリ作成時のデフォルトをprivateに設定
- [ ] public変更に管理者承認を必須化
- [ ] Secret Scanningを有効化(Enterprise)
- [ ] Push Protectionを有効化

### 個人設定
- [ ] 二要素認証を有効化
- [ ] Personal Access Tokenの有効期限を設定
- [ ] SSHキーを最新のものに更新
  

8.4 環境変数管理のベストプラクティス

    # 悪い例 ❌
export AWS_ACCESS_KEY_ID="AKIAXXXXXXXXXX"
export AWS_SECRET_ACCESS_KEY="xxxxxxxxxxxx"

# 良い例 ✅
# AWS CLIのプロファイル機能を使用
aws configure --profile myproject

# 開発環境では.envrcとdirenvを使用
# .envrc(.gitignoreに追加済み)
export AWS_PROFILE=myproject

# 本番環境ではシークレットマネージャーを使用
# AWS Secrets Manager / HashiCorp Vault / 1Password CLI
  

9. よくある質問(FAQ)

Q: 「1分間」は本当に短いのか?

A: コンピュータの世界では1分は長いですが、「発見される」という点では非常に短いです。

  • GitHubの検索インデックスは即時ではない
  • ボットが巡回していても、全リポジトリを監視しているわけではない
  • ただし、「短い」ことと「安全」は別問題

結論: 短いが、ゼロリスクではない。予防的対応を推奨。

Q: ローテーションが面倒で先延ばしにしてしまう

A: 以下の考え方で優先度をつけてください。

優先度 シークレットの種類 理由
🔴 最高 本番環境のDB認証情報 直接的なデータ漏洩リスク
🔴 最高 AWSルートアカウントキー 全リソースへのアクセス
🟡 高 外部APIキー(課金あり) 金銭的被害
🟡 高 GitHub Token(repo権限) 他リポジトリへの影響
🟢 中 開発環境の認証情報 本番への影響は限定的
🟢 中 読み取り専用APIキー 情報漏洩のみ

Q: 上司/チームへの報告は必要か?

A: 以下の基準で判断してください。

報告すべき場合:

  • 本番環境の認証情報が含まれていた
  • 顧客データ・個人情報が含まれていた
  • 会社のセキュリティポリシーで報告が義務付けられている
  • 不正利用の痕跡がある

報告は任意の場合:

  • 個人プロジェクトのみ
  • シークレットが含まれていないことを確認済み
  • 開発環境のみで本番への影響なし

Q: 履歴からシークレットを完全に消すべき?

A: ローテーション済みなら、必須ではありません

    # 履歴から削除する場合(force push が必要)
git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch path/to/secret" \
  --prune-empty --tag-name-filter cat -- --all

# または BFG Repo-Cleaner(より高速)
bfg --delete-files .env
  

注意:

  • すでにpublicだった場合、履歴削除しても clone済みのコピーは消せない
  • ローテーション済みなら、旧シークレットは無効化されているので被害なし
  • 監査要件がある場合のみ履歴削除を検討

Q: 「.gitignoreに追加したから大丈夫」と思っていたのに漏れた

A: これが 最もよくある勘違い です。

.gitignoreは「今後のコミット」にしか効かない。過去のコミットには効果がない。

    # こういう流れで事故が起きる
git add .env          # ← ここでコミットされる
git commit -m "init"
# ...後日...
echo ".env" >> .gitignore
git add .gitignore
git commit -m "add gitignore"
# → .envは今後追加されないが、最初のコミットには残っている!
  

確認方法:

    # 過去のコミットに.envが含まれていないか確認
git log --all --full-history -- "**/.env*"

# 全履歴スキャン
gitleaks detect --source . --verbose --log-opts="--all"
  

対策: 詳しくは「7. .gitignoreしても過去のコミットに残っている問題」を参照。


10. まとめ:パニックではなくプロセスで対応する

❌ やってはいけないこと

NG行動 理由
パニックになって何もしない 時間が経つほど被害が拡大する可能性
「たぶん大丈夫」で放置 確認しないと本当に大丈夫かわからない
証拠を消して隠蔽 後から調査できなくなる、信頼を失う

✅ やるべきこと

行動 効果
まず状況を記録 正確な対応と報告が可能になる
チェックリストに沿って対応 漏れなく確認できる
予防的にローテーション 最悪のケースを防げる
再発防止策を導入 同じ失敗を繰り返さない

最後に: セキュリティインシデントは誰にでも起こりえます。重要なのは「起こさないこと」ではなく「起きた時に適切に対応できること」です。この記事のチェックリストをブックマークしておき、もしもの時に冷静に対応できるようにしておきましょう。


参考リンク