GitHubに秘密情報を誤プッシュした:3時間以内の対処フローチャート
結論: まず対象サービスのコンソールを開き、credentialを無効化する。git履歴の削除はその後でよい。5分以内に動けるかどうかで被害規模が変わる。
.env ファイルを git add . でパブリックリポジトリにプッシュした直後、「git rm で消せばいいか」と思うのは自然な反応だ。しかしGitHub公式ドキュメントは、最初にやるべきことを明確に述べている。
if the sensitive data you need to remove is a secret (e.g. password/token/credential), as is often the case, then as a first step you need to revoke and/or rotate that secret.
「まず無効化。履歴削除はその後」——この順序が、被害を最小化する正しい判断だ。
buildmvpfast.comの報告によると、脅威アクターはIAMクレデンシャルをパブリックリポジトリから5分以内に収集するとされている(※GitGuardian 2025 State of Secrets Sprawl / GitHub自己報告よりbuildmvpfast.comが引用)。git履歴を書き換えている間にも、credentialはすでに使われている可能性がある。
この記事では次の内容を整理する。
- 6ステップの対処フロー全体像
- サービス別のcredential無効化手順
- git履歴削除の推奨ツールと手順
- force push後もGitHubサーバー上に残るデータと対処
- 履歴書き換えの副作用と、やらないほうがいいケース
対処フロー全体図 — まず6ステップを把握する
パニック状態で細部から読み始めると時間を失う。まず全体の流れを確認してから、Step 1に進む。
誤プッシュ発覚
↓
[確認 / 0〜5分] git log で何をプッシュしたかを特定する
↓
[Step 1 / 5〜15分] Credential を今すぐ無効化する(← 最優先)
↓
[Step 2 / 5分] パブリックリポジトリをPrivate化する
↓
[Step 3 / 30〜60分] git-filter-repo または BFG で履歴を削除する
↓
[Step 4 / 10分] force push → GitHub Support へ連絡する
↓
[Step 5 / 10〜30分] Collaboratorsへ周知し、rebaseで再統合する
↓
[Step 6] 再発防止設定(gitleaks・.gitignore・IAMロール移行)
リポジトリがもともとプライベートの場合、Step 2はスキップできる。ただし後述する通り、プライベートでもcredential無効化(Step 1)は同様に必要だ。
[確認] まず何をプッシュしたかを特定する
行動より先に、対象を正確に把握する。「たぶん .env だけ」という自己判断で動き始めると、後から別のファイルが含まれていたことに気づくことがある。
対象ファイルとコミットハッシュを特定するコマンドを実行する。
git log --all --name-status --pretty=short --graph -- 対象ファイルパス
出力から確認すべき4点は次の通りだ。
- どのファイルがコミットされているか
- いつ(どのコミットハッシュで)コミットされたか
- リポジトリがパブリックかプライベートか
- フォークやPullRequestが存在するか
Zenn yoshiki_aiの記事によると、GitHubの自動シークレット検出メールが約3分で届いたとの報告がある。メールが届いた場合、GitHubのスキャンが対象のcredentialをすでに検出済みであることを意味する。届いていない場合でも、自動検出の対象外である可能性があるだけで、安全を意味しない。
[Step 1] Credential を今すぐ無効化する — 履歴削除より先に
このステップが最重要だ。git履歴の削除に30〜60分かけている間も、無効化されていないcredentialは攻撃者に使われ続けるリスクがある。
なぜ履歴削除より先なのか
GitHub公式ドキュメントは次のように述べている。
Once the secret is revoked or rotated, it can no longer be used for access, and that may be sufficient to solve your problem.
credentialを無効化すれば、攻撃者はそのkeyを使えなくなる。無効化だけで問題が解決する場合もある——これはGitHub公式の見解だ。
DEV.to Alan Westの記事では、パブリックリポジトリへのAWSキー公開から11分後に暗号通貨マイニングのために使用され、数千ドルの課金が発生した事例が紹介されている。
Rotate the credential immediately. Not after you clean up the repo. Right now. Assume the credential is compromised the moment it touches a public commit, even for one second.
履歴を書き換えるよりも先に、対象サービスのコンソールを開く。
サービス別 無効化手順
主要サービスの無効化場所を次の表に整理する。各サービスのUIは変更されることがあるため、最新のパスはサービス公式ドキュメントを確認すること。
| サービス | 無効化場所(参考) | 操作 |
|---|---|---|
| AWS IAM アクセスキー | AWS Console → IAM → Users → Security credentials | Inactive化 → 新キー発行 → 旧キー削除 |
| GitHub PAT | Settings → Developer settings → Personal access tokens | 該当トークンをRevoke |
| Google Cloud API キー | console.cloud.google.com → APIとサービス → 認証情報 | 該当キーを削除・新規作成 |
| OpenAI API キー | platform.openai.com → API keys | 該当キーをRevoke |
| X (Twitter) API | developer.twitter.com → Projects & Apps | キー再生成 |
上記の各コンソールパスは参考として示したものだ。Zenn yoshiki_aiの記事も参照のこと。
AWS IAM の CLIコマンド手順
DEV.to Alan Westの記事では、次の手順でAWSキーをローテーションすることが推奨されている。削除より先にInactive化するのは、新キーの動作確認後に元に戻せる(reversible)からだ。
# 1. 古いキーをInactiveに変更(reversible・動作確認まで残せる)
aws iam update-access-key \
--user-name <username> \
--access-key-id AKIA... \
--status Inactive
# 2. 新しいキーを発行する
aws iam create-access-key --user-name <username>
# 3. 新キーの動作を確認した後、古いキーを削除する
aws iam delete-access-key \
--user-name <username> \
--access-key-id AKIA...
無効化後は、漏洩したキーIDがその後も使われていないかCloudTrailで確認する。AWS Security Blogでは、CloudTrail Insightsを使った不審なAPIコール検出の手順が解説されている。
[Step 2] パブリックリポジトリをすぐPrivate化する
credential無効化が完了したら、次に取れる被害局限措置がPrivate化だ。
GitHubの操作は Settings → Danger Zone → Change visibility → Make private から行う。
「Private化すれば安全」という認識は誤りだ。Private化した時点ですでにスキャンされている可能性を前提に行動する必要がある。
GitHub公式ドキュメント(About secret scanning)によると、GitHubにはSecret Scanningパートナープログラムがある。AWS・Stripe・Vercel等のパートナープロバイダーはパブリックリポジトリ検出時に自動通知を受け取る仕組みがあるため、公開されていた時間が数分でも、パートナー企業側ではすでに検出している可能性がある。
リポジトリがもともとプライベートの場合でも、Zenn omakaseの事例分析が示すように、GitHub Access Tokenの漏洩からCI/CDを悪用した本番環境への侵入が起きている。credentialが含まれていた場合は、リポジトリの可視性にかかわらずStep 1の無効化が必要だ。
[Step 3] Gitの履歴から削除する — ツール選定と手順
Step 1〜2が完了した後、本丸の作業に入る。Gitの履歴にcredentialが残ったままでは、フォーク・クローンを経由した漏洩が続く可能性がある。
GitHubからの情報漏洩が起きる経路については/articles/github-data-leak-attack-vectorsで解説しているが、このステップで対処するのは「Gitオブジェクトとして保持されている過去のコミット」だ。
ツール選定早見表
| ツール | 推奨度 | 前提条件 | 特徴 |
|---|---|---|---|
| git-filter-repo | ★推奨(GitHub公式現行) | Python | 高速・公式推奨 |
| BFG Repo-Cleaner | 代替(大規模リポジトリ向け) | Javaが必要 | 大規模向け・高速 |
| git filter-branch | 非推奨(deprecated) | なし | 低速・廃止予定 |
git-filter-repo の手順
git-filter-repoはGitHubが公式に推奨するツールだ。まずインストールする。
brew install git-filter-repo
特定のファイルを履歴ごと削除する場合は次のコマンドを実行する。PATH-TO-FILE-WITH-SENSITIVE-DATA を実際のファイルパスに置き換える。
git-filter-repo \
--sensitive-data-removal \
--invert-paths \
--path PATH-TO-FILE-WITH-SENSITIVE-DATA
パスワードや接続文字列など特定の文字列を履歴から置換したい場合は、対象の文字列をリストアップしたファイル(passwords.txt)を用意して次のように実行する。各行に「対象文字列==>置換後文字列」の形式で記述する。
git-filter-repo \
--sensitive-data-removal \
--replace-text ../passwords.txt
履歴書き換えが完了したら、force pushでリモートに反映する。
git push --force --mirror origin
BFG Repo-Cleaner の手順(Javaが使える環境での代替)
Zenn yoshiki_aiの記事では、BFG Repo-CleanerによるAPIキー削除の手順が紹介されている。Javaが必要なため、Javaのインストール状況を事前に確認してから進める。
基本的な流れはミラークローン → ファイル削除または文字列置換 → git reflog expire --expire=now --all && git gc --prune=now --aggressive → force pushとなる。
force push 前の必須確認事項
force pushは破壊的な操作のため、事前に次の点を確認する。
-
ブランチ保護の解除: ブランチ保護が有効な場合はforce pushが拒否される。
Settings → Branchesから一時的に解除し、force push後に必ず再設定する。 -
開いているPRのマージまたはクローズ: 開いているPullRequestが存在する状態でforce pushを行うと、PRのdiffが破損する。可能であれば事前にマージまたはクローズしてから実施する。
-
Collaboratorsへの事前連絡: force push後にCollaboratorsが
git pullを実行すると汚染された履歴が戻ることがある。後述のStep 5を事前に周知しておく。
[Step 4] force push後にもGitHubサーバー上に残るデータ — GitHub Supportへ連絡する
「force pushで完全に消えた」という認識は誤りだ。GitHub公式ドキュメントは、force push後もGitHubサーバー上に残り続けるデータとして4つの経路を挙げている。
- フォーク: 他のユーザーがフォークを持っている場合、そのフォーク内に古いコミットが残る。自分ではコントロールできない。
- Collaboratorsのローカルクローン: ローカルにクローンしたリポジトリには古い履歴がそのまま残っている。
- PRのキャッシュビュー: クローズ済みのPullRequestのdiffがUIから参照可能な状態で残ることがある。
- SHA-1ハッシュによる直接アクセス: 古いコミットのSHA-1ハッシュを知っていれば、GitHubのAPIやUIから直接参照できる。
これらを対処するには、GitHub Support Portal(support.github.com)への連絡が必要になる。Supportに依頼できる内容は次の通りだ。
- クローズ済みPRのキャッシュビューの削除
- サーバーサイドのGarbage Collection実行
- SHA-1ハッシュによる直接アクセスの無効化
ただし、GitHub公式ドキュメントは次の点も明記している。credentialを無効化済みで攻撃リスクが軽減されていると判断される場合、Supportがキャッシュ削除に対応しない可能性がある。Step 1の無効化が完了しているかどうかが、Supportへの連絡の前提条件となる。
[Step 5] Collaboratorsへの周知と再統合手順
チームメンバーが存在する場合、周知の遅れが「汚染された履歴の再混入」につながる。
周知に含めるべき内容は次の4点だ。
- どのファイルが削除されたか
- force pushが実施済みであること
git pullではなくgit cloneし直すよう依頼すること- 統合する場合は
mergeではなくrebaseを使うよう依頼すること
git pull を実行すると、ローカルに残っている古い履歴がリモートにマージされて汚染された状態に戻ることがある。また merge を使うとmerge commitが古い履歴を再導入するリスクがある。GitHub公式ドキュメントでも、collaboratorsへのrebase依頼が推奨されている。
フォーク所有者がいる場合は直接連絡し、フォークの削除または同様の履歴書き換えを依頼する。対応してもらえるかどうかはフォーク所有者次第だが、連絡しておくことがリスク管理として重要だ。
組織として連絡フローを整備していない場合のインシデント対応全体についてはセキュリティインシデント対応SOPを参照のこと。
注意 — 履歴書き換えの副作用と、事前に確認すべきこと
git-filter-repoやBFGを使えば「完全に消える」とは言い切れない。GitHub公式ドキュメントが明示する副作用を正確に把握しておく。
1. Collaboratorsによる再汚染リスク
force push後にCollaboratorsが git pull を実行すると、ローカルに残っていた古い履歴がリモートに戻る。Step 5の周知徹底が前提になる。
2. 全コミットハッシュの変更
履歴を書き換えると、すべてのコミットハッシュが変わる。CIパイプラインやデプロイスクリプトがコミットハッシュを参照している場合、それらが破損する可能性がある。
3. ブランチ保護との競合
force pushのためにブランチ保護を一時解除する必要がある。解除後の再設定を忘れると、その間の保護が失われる。
4. クローズ済みPRのdiff破損
機密データが含まれるコミット以降のすべてのPRのdiffが参照不能になる。コードレビューの記録が失われることを意味する。
5. コミット・タグ署名の無効化
git-filter-repoはコミット・タグ署名を削除する。署名付きコミットを運用している場合は、再署名が必要になる。
これらの副作用を踏まえると、「credential無効化だけで履歴削除を省略する」という選択肢が有力になるケースがある。GitHub公式ドキュメントが述べているように、credentialを無効化すれば攻撃者はそのkeyを使えなくなり、それで十分な場合もある。副作用のコストと残存リスクを比較して、どちらの対応を取るかを判断する。
Secret Scanning の確認 — 無料プランでできることとできないこと
「Secret Scanningは有料プランだけ」という誤解がある。パブリックリポジトリでは無料で利用できる。
| リポジトリ種別 | Secret Scanning | Push Protection |
|---|---|---|
| 個人アカウント所有・パブリック(2024年3月11日以降に作成) | デフォルト有効 | デフォルト有効 |
| 個人アカウント所有・パブリック(それ以前に作成) | 手動で有効化 | 手動で有効化 |
| Organization所有・パブリック | 手動で有効化 | 手動で有効化 |
| プライベート・内部リポジトリ | GitHub Secret Protection必要 | GitHub Secret Protection必要 |
GitHub Changelog(2024年3月11日)によると、個人アカウントが所有する新規パブリックリポジトリには2024年3月11日以降、Secret ScanningとPush Protectionがデフォルトで有効になっている。
AppSec Santaの解説によると、プライベート・内部リポジトリ向けのSecret ScanningはGitHub Secret Protection(旧Advanced Security)として独立した製品で提供されている。価格はGitHubの公式料金ページを参照のこと。
buildmvpfast.comの報告では、GitHubは2024年に3,900万件のシークレットが漏洩したと報告しており、そのうちPush Protectionが440万件を事前にブロックしたとされている(※GitGuardian 2025 State of Secrets Sprawl / GitHub自己報告よりbuildmvpfast.comが引用)。
有効状態の確認は GitHub → Settings → Code security → Secret scanning から行える。
再発防止 — 同じ事故を繰り返さない3つの設定
今回の対応が完了した後、次の3点を整備することが再発防止の基本になる。
1. .gitignore の確認と整備
.env ファイルが .gitignore に含まれていなかったことが、今回のような事故の直接的な原因になる。最低限、次のパターンをプロジェクトルートの .gitignore に追加する。
# 環境変数・認証情報
.env
.env.*
*.pem
*.key
credentials.json
service-account.json
既存のコミットに含まれている場合は git rm --cached <ファイルパス> でトラッキングを解除した上で .gitignore に追加する。
2. gitleaks の導入とpre-commitフック統合
gitleaks は、Gitリポジトリ内のシークレット検出に特化したオープンソースツールだ。pre-commitフックとして統合することで、コミット前に機密情報を検出して止めることができる。
インストールは次のコマンドで行う。
brew install gitleaks
pre-commitフックとして統合する場合、.pre-commit-config.yaml に次の設定を追加する。rev の値はGitHubのリリースページで最新バージョンを確認して設定する。
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.x.x # 最新バージョンをリリースページで確認する
hooks:
- id: gitleaks
DEV.to Alan Westの記事でも、gitleaksをpre-commitフックとして設定することが推奨されている。
3. 長期クレデンシャルからIAMロールへの移行
AWS Security Blogによると、AWSのCIRT(Customer Incident Response Team)が観測するセキュリティインシデントの中で、長期クレデンシャルの漏洩が最も多い攻撃起点として認定されている。
IAMアクセスキー(長期クレデンシャル)を根本的に廃止し、IAMロールと一時的なクレデンシャルに移行することが、この種の事故を構造的に防ぐ方法だ。特にCI/CD環境では、GitHub ActionsのOIDC連携によりIAMアクセスキーを一切使わない構成が可能になっている。
この移行は一人のエンジニアが週末に完了できる作業ではなく、インフラ設計全体の見直しを伴う。今回の急性対応が完了した段階で、組織としての次の課題として取り上げる必要がある。
gitleaksの全社導入・IAMロールへの移行・pre-commitフックのCI/CD組み込みを組織として整備するには、インフラ設計の見直しが必要になる。
よくある質問
Q. git rm してforce pushしたが、それで完全に消えた?
消えていない可能性がある。GitHubサーバー上には、フォーク・Collaboratorsのローカルクローン・PRのキャッシュビュー・SHA-1ハッシュによる直接アクセスという4つの経路で古いデータが残ることがある。Step 4を参照してGitHub Support Portalに連絡し、キャッシュ削除を依頼することを検討する。
Q. プライベートリポジトリにプッシュした場合、危険度は変わる?
credentialが含まれている場合はリスクが変わらない。Zenn omakaseの事例が示す通り、プライベートリポジトリでもGitHub Access Tokenが漏洩した後、CI/CDを経由した本番環境への侵入が起きている。credentialの無効化(Step 1)はリポジトリの可視性にかかわらず必要だ。
Q. force push前にブランチ保護の解除を忘れた場合は?
force pushがエラーで拒否される。Settings → Branches から対象ブランチの保護設定を確認し、一時的に解除してforce pushを実施する。完了後は必ず保護設定を再度有効にする。
Q. Secret Scanningが有効かどうかはどこで確認できる?
GitHub → Settings → Code security → Secret scanning で確認できる。GitHub Changelog(2024年3月11日)によると、2024年3月11日以降に個人アカウントで作成したパブリックリポジトリはデフォルトで有効になっている。
Q. credentialの無効化だけで、履歴削除はしなくていいケースはある?
ある。GitHub公式ドキュメントは「credentialが無効化されれば攻撃者はそのkeyを使えなくなり、それで十分な場合もある」と明記している。履歴削除にはコミットハッシュ変更・CI/CD破損・署名無効化等の副作用があるため、リスクとコストを比較した上で判断する。