secrets-in-git-history について
Git リポジトリ内の認証情報漏えいや組織に関する手掛かりを調べるセキュリティスキルです。削除済みの秘密情報やコミット上の識別情報が残り得るため、全履歴と全参照を調査します。
主な機能
- 01ミラークローンと全参照のスキャン
- 02TruffleHog と gitleaks による検出
- 03履歴内の文字列検索
- 04コミットメールと noreply ID の確認
- 05検出結果と誤検知の評価
- 06コミット情報を含む証拠の記録
活用シーン
- 01現行ブランチから削除された認証情報の発見
- 02コミット履歴からの開発者識別情報の整理
- 03リポジトリ履歴にあるインフラ情報の調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ useosint/ skills --skill secrets-in-git-historyインストール後、Claude Code で/secrets-in-git-historyを入力して読み込まれたか確認します。
同梱ファイルreference/git-archaeology.mdreference/high-signal-indicators.md
詳細
Git 履歴に残るシークレット
リポジトリには、3 種類の情報資産が含まれています。実在するメールアドレスを持つ人物の一覧、組織のインフラストラクチャのマップ、そして公開するつもりのなかった認証情報の保管場所です。コストのかかる間違いは、作業ツリーをスキャンすることです。HEAD から削除されたシークレットも履歴には永久に残り、ブランチから削除されたコミットもフォークネットワークを通じて到達可能なままです。チェックアウトされたものだけをスキャンするのは、そのシークレットが確実に削除された場所だけを探すことになります。
手元にある情報と、調査の始め方
| 手元にある情報 | まず調べるもの | 理由 |
|---|---|---|
| 組織名 | 公開されている組織メンバー、次に個人リポジトリ | 企業のリポジトリはレビューされますが、個人のリポジトリはレビューされません |
| 開発者の名前またはハンドル | その人物のリポジトリ全体にあるコミットメールアドレス | 他の方法では得られないメールアドレスが見つかります |
| コミットメールアドレス | 各ホストで逆引き検索し、noreply ID があれば解決する | 組織やプラットフォームをまたいでアカウントを結び付けます |
| 認証情報の漏えいが疑われる場合 | ミラークローンに対して両方のスキャナーを実行し、すべての ref を対象にする | HEAD だけのスキャンでは、肝心な部分を見逃します |
| 特定の文字列(ホスト名、キーのプレフィックスなど) | すべての ref を対象に git log -S でピックアックス検索する | いつ追加され、いつ削除されたかが分かります |
| 稼働中のドメイン | 公開された .git がないか確認する。法的な注意事項を参照 | 認可を得ている場合、Web サーバーから履歴全体を取得できます |
| 会社の Web サイトしかない場合 | 組織の内部ドメイン名をコード検索する | 組織との明白なつながりがないリポジトリを見つけられます |
コミットメールアドレスの漏えい
Git はすべてのコミットに作成者の識別情報を記録します。これは検証済みではなく、自己申告です。これは両刃の剣です。メールアドレスは簡単に偽装できる一方で、コードホスト上の ID と実際のメールボックスを結び付ける、最も信頼性の高い公開情報でもあります。
git clone --mirror https://github.com/example-org/example-repo.git repo.git
git --git-dir=repo.git log --all --format='%an <%ae>' | sort -u
GitHub の Web UI にはコミットメールアドレスが表示されないため、非公開だと思われがちです。しかし、非公開ではありません。任意のコミット URL に .patch を追加すると、From: ヘッダーに作成者の名前とメールアドレスが含まれるメール形式のパッチが表示されます。API では commit.author.email から同じ情報を取得できます。
curl -s https://github.com/example-org/example-repo/commit/<sha>.patch | head -5
curl -s https://api.github.com/repos/example-org/example-repo/commits/<sha> | jq .commit.author
noreply の形式は、きちんと理解しておく価値があります。 メールアドレスのプライバシーを有効にしているユーザーは、[email protected]、または新しい形式の [email protected] を使ってコミットします。後者の形式からは、アカウントの数値ユーザー IDが分かります。この ID は変更されず、アカウントが何度名前を変更してもそのまま残るため、古いコミットから現在の所有者を特定できます。
curl -s https://api.github.com/user/12345678 | jq '.login, .created_at'
これにより、名前変更を乗り越えて追跡できます。長い間使われていないハンドル名の古いコミットも、その人物の現在の ID につながります。対象者側で起こるもう一つの問題は、何年もコミットした後でメールアドレスのプライバシーを有効にすることです。その日より前のコミットにはすべて実際のメールアドレスが含まれるため、全履歴から作成者一覧を取得してください。
組織をソーシャルグラフとして列挙する
企業のリポジトリはレビューされますが、個人のリポジトリはレビューされません。開発者は同じインフラストラクチャをその両方に置くことがあります。たどるべき経路は、組織から人、そして個人アカウントです。
組織の公開メンバー登録は任意であるため、情報は不完全です。そこで、複数の情報源を照合してください。https://api.github.com/orgs/<org>/public_members からは、公開することを選んだメンバーを取得できます。一方、組織内のすべてのリポジトリから作成者一覧を取得すれば、一度も公開メンバーにならなかった人や、すでに組織を離れた人も含め、実際にコミットした人全員が分かります。
各人物について、リポジトリ、gist、フォロワー、フォロー中のアカウント、スターを付けたリポジトリ、ウォッチ中のリポジトリを取得してください。あまり活用されていないのはスターとフォローです。プライバシーのために整理する人はほとんどおらず、プロフィール項目よりも、関心事、勤務先、個人プロジェクト、仕事上のつながりを正直に示します。同じ目立たない社内ツールらしきものにスターを付けている開発者の集まりは、同僚同士です。
公開アクティビティイベントで確認できるのは直近の短い期間ですが、公開イベントストリームは過去のアーカイブデータセットとしても公開されており、分析対象を何年も前まで広げられます。コミットのタイムスタンプをまとめて分析すると、勤務時間帯とタイムゾーンが分かります。
コード検索とその実際の限界
ホストのコード検索では、公開リポジトリ全体から文字列を検索できます。この組織だけが使いそうなものを検索してください。内部ホスト名、非公開パッケージ名、クラウドアカウント ID、メールのドメインなどです。会社名ではマーケティング文言が見つかりますが、内部ドメインからはインフラが見つかります。
構文よりも限界のほうが重要です。どれも気づきにくい見落としにつながるからです。コード検索の対象はデフォルトブランチのみで、履歴も他のブランチも対象外です。そのため、削除されたシークレットは仕組み上、検索では見つかりません。すべてのリポジトリがインデックス化されているわけではありません。非常に大きなリポジトリや、独自の活動がないフォークは、一般に除外されます。通常、認証が必要で、レート制限も厳しく設定されています。また、照合はトークン単位で行われるため、長いトークン内の部分文字列は、期待どおりに一致しないことがあります。
コード検索は、クローンするリポジトリを特定するための探索ツールとして使ってください。実際の調査はローカルで行います。
削除後も残るものすべて
- HEAD から削除したシークレットも、履歴には残ります。 ファイルの削除はコミットであり、消去ではありません。履歴を書き換えても、クローン、フォーク、キャッシュには反映されません。そして、削除すれば修正できたと思い込むため、その後にシークレットをローテーションする人はほとんどいません。
- フォークネットワーク内のコミットは、ブランチが削除された後も、PR がマージされずにクローズされた後も、フォークが削除された後も、SHA で引き続き参照できます。 リポジトリを非公開にしても、フォークに届いたものは取り消せません。また、強制プッシュされたコミットは消えるのではなく、参照されなくなるだけです。
- Gist は非公開ではなく、非掲載です。URL を知っている人なら「秘密の」Gist を読めます。また、URL はログ、チャット、チケットに漏れることがあります。
- 公開リポジトリの CI ログは公開されています。 既知のシークレット値のマスキングは、値が Base64 エンコード、連結、URL エンコードされていたり、サブプロセスによって出力されたりすると失敗します。Issue や PR の添付ファイルも、不透明な URL で提供され、Issue やリポジトリがなくなった後も取得可能なままです。
適切なスキャン
ミラークローンを作成し、両方のスキャナーを実行します。検出ルールと誤検知の傾向は異なり、どちらももう一方を完全に包含していないためです。次に、検出ルールのない文字列をピックアックス検索します。内部ドメイン、クラウドアカウント ID、設定ファイルに記載されたホスト名などです。
trufflehog git file://./repo.git
gitleaks detect --source=. -v
git log --all --source -S'internal.example.com' --oneline
git log --all --diff-filter=D --name-only --format='%H %aI %an'
検証に関する注意が一つあります。 TruffleHog は、候補のシークレットを使ってプロバイダーの API を呼び出し、それが有効かどうかを確認できます。これは、他人の認証情報を使って第三者とやり取りする行為であり、その記録は相手のログに残ります。許可を得た評価の範囲内では、通常想定される行為です。それ以外では、行わないでください。
コマンドはreference/git-archaeology.mdを参照してください。検索対象と、ヒットした項目のトリアージ方法についてはreference/high-signal-indicators.mdを参照してください。
公開されている .git ディレクトリ
作業ツリーをウェブルートにコピーするデプロイでは、.git も一緒に公開されます。そして、.git/config、.git/HEAD、オブジェクトストアから、ソース、認証情報、作成者の ID など、履歴全体を再構築できます。
検索インデックスや既存のスキャン結果を通じて、そのようなパスが存在すると確認することは受動的な行為です。取得する行為は受動的ではありません。 .git ディレクトリのダウンロードは、システムへのアクセスであり、データの取得です。設定ミスがあっても、それは許可を意味しません。書面で許可された場合に限ってください。それ以外の場合は、報告してください。
ここで誤りが生じます
- 作者の身元は自己申告です。 誰でも他人の名義でコミットできます。コミット内のメールアドレスは作者であることの証明ではなく、単なる申告です。例外は署名付きコミットで、確認するのは文字列ではなく署名です。
- コミット数の大半はボットによるものです。 CI、依存関係ボット、マージの自動化により、合成された身元で大量のコミットが作成されます。人について結論を出す前に、これらを除外してください。
- リベースやスカッシュマージによって作者情報は書き換えられます。 コミッターはマージを実行した人になり、スカッシュすると複数の作者が一人にまとめられます。ログに見当たらないからといって、プロジェクトに関与していないとは限りません。
- タイムゾーンの推定には不確実性があります。 ノートパソコンは移動し、オフセットは手動で設定されることもあり、CIはUTCでコミットします。あくまで補助的な情報として使ってください。
- テスト用フィクスチャやドキュメントの例は、認証情報とまったく同じように見えます。 また、プロバイダーのサンプルが数千ものリポジトリに広まることがあります。まず検索してください。
- 公開を前提としたキーは漏えいではありません。 公開可能なキーやリファラー制限付きのブラウザーキーは、配布することが前提です。これを侵害として報告すると、実際の問題に関する調査結果まで信頼を失います。
- 同名の組織やタイポスクワッティングの対象は、調査対象そのものとは限りません。 また、履歴だけに残る問題は、現在も残っている問題より重大な場合がよくあります。ローテーションせずに削除するのが一般的だからです。
信頼度の評価
- 確認済み — noreply の数値 ID からアカウントを特定できる、または同一のコミット用メールアドレスが、その人物とすでに関連付けられている複数のアカウントで使われているなど、身元の関連性が確認できる場合です。認証情報の形式が有効で、周囲の文脈からスコープが確認でき、コミット SHA と日付も特定できる場合です。
- 可能性が高い — 特徴的なメールアドレスやハンドルが複数のリポジトリで繰り返し使われ、コミット時刻にも一貫性がある場合、またはテスト用パス以外の実際の設定ファイルに認証情報らしき文字列がある場合です。
- 未確認 — 署名のない単一コミットの作者文字列、ありふれたハンドル、フィクスチャやドキュメントの例でのスキャナー検出、スコープが不明な認証情報です。
- 却下 — 文書化されたプレースホルダー、公開可能なキー、または有効期限切れの一時的な認証情報を、現在有効な漏えいとして提示したものです。
調査結果ごとに、リポジトリ、コミット SHA、日付、ファイルパスを記録してください。SHA は変更できない参照情報ですが、行番号はそうではありません。
具体例
目的:サイトで幹部しか紹介されていない企業のエンジニアリングチームを特定します。
内部ドメイン svc.example-corp.net でコード検索すると、企業名を含まないリポジトリが3つ見つかります。それらをミラーとしてクローンすると、作者メールアドレスが14件見つかり、そのうち11件は企業用、3件は個人用です。
ある作者は [email protected] としてコミットしています。数値 ID を解決すると、現在のユーザー名は別のものだと分かります。アカウント名が変更されており、古いハンドルには、現在のハンドルにはないカンファレンス登壇記録と個人ブログへのリンクがあります。
行き止まり:gitleaks がテスト用フィクスチャ内の AWS 形式のキーを検出し、その文字列を検索すると、AWS 自身のドキュメントにそのまま掲載されていることが分かります。これは除外し、誰かが再び報告しないよう、除外したことも記録します。
実際に見つかったのは、2年前に追加され、同じ週に削除された terraform.tfstate で、履歴から復元できました。有効な認証情報はありませんが、内部ホスト名が4つとクラウドアカウント ID が含まれています。これは find-hidden-subdomains 用のインフラです。
評価:コミットの作者情報は自己申告であり、裏付けがないため、チーム名簿は可能性が高いです。数値 ID は変更されないため、アカウント名の変更との関連性は確認済みです。
ピボット
| 新しいセレクター | 移動先 |
|---|---|
| コミット作成者のメールアドレス | what-an-email-reveals、what-leaked-about-you |
| ハンドル、変更後のアカウント名、数値 ID | hunt-a-handle |
| コミットや CODEOWNERS から分かる実名 | find-anyone |
| 設定ファイルから分かる内部ホスト名 | find-hidden-subdomains、who-owns-this-domain |
| クラウドアカウント ID、バケット、IP アドレス | find-exposed-servers、google-like-a-spy |
| コミットされたドキュメントや画像 | secrets-in-file-metadata |
| 組織構造とベンダースタック | x-ray-a-company |
| 削除されたリポジトリや削除済みページ | read-deleted-pages |
| 公開ダンプに含まれる認証情報 | find-leaks-in-the-wild |
| コントリビューターネットワーク | graph-the-network |
法律、開示、そして絶対に守るべきルール
見つけた認証情報を使って認証してはいけません。 動作確認のためでも、読み取り専用でも、一度たりとも使用してはいけません。ほとんどの法域ではコンピューター不正使用関連法に基づく不正アクセスにあたり、公開されているからといって許可を得たことにはなりません。有効性は形式、文脈、メタデータのみから判断してください。それ以外の方法は使わないでください。../../ETHICS.mdを参照してください。
有効そうに見える認証情報を見つけた場合は、開示する義務が生じます。セキュリティ連絡先、security.txt の窓口、またはホストの脆弱性報告窓口を通じて速やかに報告してください。リポジトリ、コミット SHA、ファイルパスを伝え、履歴を書き換えるだけでは不十分で、認証情報をローテーションする必要があることを明記してください。伏せ字にした参照情報のみを保持し、何も公開しないでください。自動シークレットスキャン連携を導入しているホストでは、すでにトークンが無効化されている場合がありますが、それでも誰かに知らせる義務はなくなりません。
公開リポジトリのクローンは通常の利用ですが、大量のクローンや高頻度の API クエリにはレート制限が適用され、利用規約に違反するおそれがあります。コミットメールアドレスは、リポジトリの状態にかかわらず、GDPR や同等の法制度における個人データです。収集は必要最小限にとどめ、保存期間を設定してください。