マネーフォワードのGitHub不正アクセス事件をエンジニア視点で読み解く — なぜソースコードに本番カード情報と認証キーが入っていたのか
はじめに
2026 年 5 月 1 日、マネーフォワードが「GitHub への不正アクセス発生に関するお知らせとお詫び(第一報)」を公表しました。GitHub の認証情報が漏えいし、第三者によりリポジトリがコピーされ、ソースコードと一部の個人情報が流出した可能性があるという内容です。同時に、銀行口座連携機能を一時停止する措置もとられました。
この事案は、エンジニア視点で見ると「仕方ない部分」と「明らかにアウトな部分」がはっきり分かれる、教科書のような事例になっています。GitHub 認証情報の漏えい自体は、正直に言ってどの会社でも起こり得ます。一方で、流出したとされる中身に 本番カード保持者の氏名と下 4 桁が 370 件、そして ソースコード内に各種認証キー・パスワード が含まれていたという点は、設計と運用の問題として議論せざるを得ません。
この記事ではセキュリティエンジニアの立場から、
- 何が起きたのか(公式発表の整理)
- GitHub 認証情報はどう漏れるのか
- なぜソースコードに本番カードデータが入っていたと考えられるか
- なぜ認証キーがリポジトリに残っていたのか
- エンジニアとして今すぐやるべき対策(gitleaks, TruffleHog, 履歴クリーンアップ)
を整理します。
何が起きたのか
公式発表とニュース報道を突き合わせると、事案の構造はこうです。
- マネーフォワードが利用していた GitHub の認証情報が漏えい
- 第三者がその認証情報を悪用して GitHub にアクセスし、リポジトリをコピー
- 流出した可能性があるもの:
- ソースコード一式
- 「マネーフォワード ビジネスカード」保持者 370 件 の「カード保持者名(アルファベット)」と「カード番号下 4 桁」
- ソースコードに含まれていた各種認証キー・パスワード
- 流出が確認されていないもの: カード番号全桁、有効期限、セキュリティコード(CVV)、本番 DB の情報
- 対応:
- 不正アクセス経路となった認証情報の無効化・アカウント遮断(完了)
- ソースコードに含まれていた認証キー・パスワードの無効化と再発行(概ね完了)
- 銀行口座連携機能の一時停止(順次再開予定)
公式は「本番データベースからの漏えいは確認されていない」と明言しているので、いわゆる「DB が抜かれた」事案ではありません。攻撃者が触ったのは GitHub 上のリポジトリだけです。それでも個人情報が出てしまっているのが、この事案の特徴です。
GitHub 認証情報の漏えい自体は、完璧に防ぐのは難しい
まず最初に押さえておきたいのは、「GitHub の認証情報が攻撃者の手に渡ること」自体は、どんなに気をつけていてもゼロにはできない という点です。マネーフォワードを擁護したいわけではなく、現実問題としてそうだという話です。
GitHub の認証情報が漏れる経路は、大きく分けるとこのあたりです。
1. 開発者 PC のマルウェア感染
近年もっとも多いパターンです。Stealer 系マルウェアに感染した開発者の端末から、
- ブラウザに保存されたセッション Cookie
-
~/.gitconfigや OS のキーチェーンに保存された Personal Access Token (PAT) - SSH 秘密鍵
- クリップボード
が一括で抜き取られます。被害者本人は気づかないまま、認証情報だけが闇市場に流れます。
2. 公開リポジトリ・公開コードへの誤コミット
.env や設定ファイルを .gitignore に入れ忘れて公開リポジトリに push してしまうケース。GitHub のシークレットスキャンが自動で検知して通知してくれますが、検知前に攻撃者の自動 bot に拾われる速度の方が早いことも珍しくありません。
3. サードパーティ連携の侵害
OAuth App、GitHub App、CI/CD サービス(CircleCI など)など、GitHub に対して権限を持つ連携先が侵害されると、そこから連鎖的にトークンが流出します。CircleCI の 2023 年初頭のインシデントは記憶に新しいところです。
4. フィッシング
GitHub を装った OAuth アプリ承認ページや、偽の二要素認証ページに誘導するパターン。2FA を有効化していてもフィッシングプロキシで突破される事例があり、FIDO2 / Passkey ベースでないと完全には防げません。
GitHub は 2024 年 1 月から GitHub.com にコードを push する全ユーザーに 2FA を義務化しましたが、それでも上記 1〜3 の経路は塞ぎきれていません。「うちは 2FA を入れているから大丈夫」では止まらない というのが現実です。
ですので、GitHub の認証情報が漏れたこと自体を責めてもあまり意味がありません。問題は、漏れた後にどれだけ被害を抑えられる構造にしておけるか です。今回はここの設計に大きな穴があった、というのがエンジニアとしての見方になります。
問題の本質: ソースコードに何が入っていたのか
この事案で本当に議論されるべきはここです。流出したリポジトリの中身に、入っているべきでないものが入っていた。
1. 本番カード保持者データ 370 件
これがいちばん引っかかる部分です。「マネーフォワード ビジネスカード」のカード保持者名(アルファベット表記)とカード番号下 4 桁が、ソースコードを保管しているリポジトリの中にあったということになります。
カード番号は下 4 桁だけなので PCI DSS 上の機微データではない(トランケーションされた PAN は保存・表示が許される)という整理は可能です。クレジットカード業界では「下 4 桁」はレシートにも印字されているレベルの情報です。ただし、
- 氏名と下 4 桁の組 を 370 件分まとめて持っている
- それが本番ユーザーの実データである
という条件が揃うと、話は変わってきます。フィッシングの精度を上げるための「ターゲットリスト」として悪用できる規模です。「〇〇 ◯◯さん、お持ちのカード(下 4 桁 1234)に不審な利用がありました」という詐欺メールに名前と下 4 桁が一致した状態で書かれていたら、引っかかる人の率は跳ね上がります。
なぜこんなものがソースコードのリポジトリに入っていたのか。第一報には書かれていませんが、エンジニアとして筋を考えると、いくつかの仮説があります。
- CI / E2E テストのフィクスチャデータとして本番データの一部を流用していた
- 過去のバグ調査時に再現用としてダンプを置いた、それが消されずに残った
- マイグレーションスクリプトに固定値として埋め込まれていた
- データ移行や検証のための一時ファイルを
git addしてしまった
どれもありがちな動線ですが、本番データを開発リポジトリに置く時点で「いやこれだめでしょ」と気づくべきラインです。本番から取ってきたデータをテストで使いたい場合は、最低限でも、
- 氏名は別人の合成データに置換(仮名化)
- カード下 4 桁もダミーに置換
- そもそもリポジトリではなくシークレット管理サービス側に置く
といった処理を必須にする必要があります。GDPR や個情法の観点でも、本番個人情報をテスト環境に流用する時点でアウトに近い運用です。
2. 各種認証キー・パスワードの埋め込み
公式リリースには「ソースコードに含まれる各種認証キー・パスワードの無効化と再発行(概ね完了)」と明記されています。過去形ではなく、流出時点で確実に存在していた ということです。
これも初歩的すぎる失敗で、現代の開発であれば、
- AWS Secrets Manager / SSM Parameter Store
- HashiCorp Vault
- GCP Secret Manager
- 各 PaaS の環境変数機能
のいずれかに逃すのが標準です。コード内のハードコードは、
- リポジトリが流出した瞬間に全鍵が突破される
- ローテーションが事実上不可能(コード修正・デプロイがセットで必要)
- 誰がどの鍵にアクセスできるかが追跡できない
という三重苦になります。今回のマネーフォワードのケースでは「再発行は概ね完了」とあるので、対応として鍵を全部回しているわけですが、裏を返せば 回さないといけない数が「概ね」と表現されるくらいには大量にあった ということでもあります。
3. なぜ消えないのか — Git 履歴という落とし穴
「いや、自分のところでは最新コードには認証情報を含めていない」と言いたい開発者も多いと思います。問題は Git の履歴は消えにくい ことです。
- うっかり
git commit -m "fix"で.envをコミット →git rmした - このとき作業ディレクトリからは消えたが、過去のコミットには残っている
- リポジトリ全体をクローンされた時点で、過去履歴ごと持っていかれる
歴史の長いサービスほどこのパターンに該当する可能性が高く、「今の HEAD はクリーンだから安心」は通用しません。攻撃者は git log -p を回すだけで過去にコミットされた .env を拾えます。
エンジニアとして今すぐやるべきこと
ここからは技術観点での具体的な対応です。今回の事案を「他人事」にしないためのチェックリストとして使ってもらえれば。
1. シークレットスキャナを CI と pre-commit に組み込む
代表的な OSS は二つです。
- Go の単一バイナリ、依存なし
- 150 種類以上のシークレットパターンを内蔵
- 高速で、pre-commit フックや CI に組み込みやすい
- 「コミット前に止める」用途に最適
# pre-commit で全変更を検査
gitleaks protect --staged --verbose
# 過去履歴を全部スキャン
gitleaks detect --source . --log-opts="--all"
- 800 種類以上のシークレットパターンに対応
- 検出した鍵が今も有効かを実際に検証してくれる のが強み
- 履歴の一括スキャンや定期スキャンに向く
# Git 履歴全体を検証付きでスキャン
trufflehog git file://. --only-verified
実務的には、「pre-commit と CI に gitleaks、定期スイープに TruffleHog」 という組み合わせが現状のベストプラクティスとされています。gitleaks で「これからの混入」を止め、TruffleHog で「過去に紛れ込んだものの中で今も生きているもの」を炙り出す、という役割分担です。
2. GitHub 標準のシークレットスキャンとプッシュプロテクションを有効化
GitHub Advanced Security またはパブリックリポジトリでは、Secret Scanning とそのプッシュプロテクションが利用できます。push されようとしているコミットに既知パターンの鍵が含まれていれば、サーバ側で蹴ってくれます。OSS のフックを擦り抜けたケースの最後の砦として有効です。
3. 既存リポジトリの過去履歴をクリーンアップ
歴史の長いサービスは一度、過去履歴の全スキャンをやっておくことを強く推奨します。手順としては、
- TruffleHog や gitleaks で全履歴をスキャン
- ヒットした鍵について、まず 無効化(rotate)を最優先 で行う(履歴を消すのは後)
- 必要に応じて git-filter-repo や BFG Repo-Cleaner で履歴から該当ファイルを削除
- 共同作業者全員に再クローンを促す
順序が重要です。外部に流出した可能性がある場合は、鍵を回す前に履歴を書き換えてはいけません。攻撃者がすでにフォーク/クローンしている可能性があるなら、履歴を消しても鍵が無効化されていなければ意味がなく、むしろ「リポジトリ管理者は鍵が漏れたことに気づいた」と攻撃者に教えてしまいます。
逆に、ずっと private のままで、外部にリポジトリのコピーが出回った可能性がないと言い切れるのであれば、履歴書き換えだけで対応しても実害はありません。ただし「漏れた可能性がない」と本当に断言できるかは慎重に判断する必要があります。退職者や元委託先のローカルにクローンが残っているかもしれない、過去に短期間だけ外部メンバーがアクセスしていた、といった経路まで含めて考えると、判断に迷う場合は rotate しておくのが無難です。
4. 本番データをテスト環境に持ち込まない仕組み化
カード保持者データの 370 件はおそらくここに起因します。技術的・運用的に詰める観点としては、
- フィクスチャは合成データジェネレータ(Faker, Mimesis 等)を使う
- どうしても本番由来データが必要な場合、必ず 不可逆な仮名化・マスキング を経由
- DB ダンプを取るスクリプトに「個人情報カラムを置換する SQL」をパイプとして必ず通す
- 本番 DB → ステージング DB のレプリケーション経路にマスキング層を挟む(PostgreSQL Anonymizer など)
「本番から持ってきたいエンジニアの気持ち」を否定するのではなく、持ってきても大丈夫な状態に変換する経路を提供する のが運用設計のポイントです。
5. シークレット管理サービスへの全面移行
ハードコード撲滅は仕組みでやるしかありません。以下のいずれかは導入されているべきです。
- AWS Secrets Manager / SSM Parameter Store
- GCP Secret Manager
- HashiCorp Vault
- Doppler / Infisical などの SaaS
その上で、
- 開発・ステージ・本番で異なる鍵を発行
- 鍵には有効期限を設定
- アクセスログを監査ログに残す
- 定期的な自動ローテーション
を設定すれば、「漏れたときに即無効化できる」「漏れた範囲が分かる」運用に変わります。
6. PAT の使用方針を見直す
組織の GitHub アカウントで Personal Access Token を多用していないか、点検する価値があります。PAT は有効期限を長く取りがちで、一度漏れると影響範囲が大きい長期シークレットです。代替としては、
- GitHub App ベースの短期トークン(インストールトークンは 1 時間で失効)
- OIDC 経由 での CI/CD からの認証(AWS, GCP, Azure すべて対応)
- fine-grained PAT に切り替えてリポジトリと権限を最小化
OIDC を使えば、CI 側に長期シークレットを置く必要がそもそもなくなります。「漏れる鍵を最初から作らない」のが一番の対策です。
マネーフォワードの初動評価
ここまで厳しく書きましたが、初動対応自体は教科書通りで悪くありません。
- 認証情報の無効化を最優先で実施 → ✅
- 認証キー・パスワードの一括ローテーション → ✅
- 銀行口座連携の一時停止(影響波及の遮断) → ✅
- 第一報の即日公開 → ✅
特に銀行連携の停止は、ユーザー体験を犠牲にしてでも安全側に倒す判断で、金融サービス事業者としては妥当です。連携 API の認証情報がソースコードに含まれていた可能性を考えると、止めない方がリスクが大きい。
逆に、第二報以降で求められるのはおそらく以下の説明です。
- どの認証情報がどう漏れたのか(経路)
- なぜ本番カード情報がリポジトリに入っていたのか
- どの種別の鍵が、何個、いつまでに無効化されたのか
- 同種データの他リポジトリでの混入有無
- 再発防止策(仕組み・組織レベルでの)
この事案で本当に問われるのはここからの透明性です。
まとめ
整理するとこうなります。
| 観点 | 評価 |
|---|---|
| GitHub 認証情報の漏えい自体 | どの組織でも起こり得る。責めても意味がない |
| 本番カード情報がリポジトリ内に存在 | アウト。本番データのテスト流用は仮名化必須 |
| 認証キー・パスワードのハードコード | アウト。シークレット管理サービスへ |
| 初動対応(鍵無効化・連携停止・即日公開) | 妥当 |
| エンジニアが取るべき対策 | gitleaks / TruffleHog / 履歴クリーンアップ / OIDC / シークレット管理 |
GitHub の認証情報が漏れること自体は、止められない前提で考えるべきです。だからこそ、漏れた瞬間に「ソースコード以外なにも持っていかれない」状態にしておく のがエンジニアの仕事になります。今のリポジトリと、その全コミット履歴に、「コピーされた瞬間に詰む情報」が入っていないか。今週中に gitleaks を回して確認してみてください。
歴史の長いサービスほど、過去履歴に何が眠っているかは誰も覚えていません。マネーフォワードからは 第二報 も出ていますが、続報を読み込む前に、自分たちのリポジトリで同じことが起きたとして耐えられるかを、一度棚卸ししておくのがよいと思います。
参考記事・データ
- 『GitHub』への不正アクセス発生に関するお知らせとお詫び(第一報)|株式会社マネーフォワード
- 「管理手順から外れて誤って GitHub に保管」— マネーフォワード第二報から考える、本番データ混入を仕組みで止める方法(本サイト関連記事)
- 【重要】『GitHub』への不正アクセス発生および銀行口座連携機能の一時停止に関するお知らせ|マネーフォワード ME サポートサイト
- マネーフォワード、GitHub からソースコードと一部ユーザー情報流出か 銀行連携を一時停止|ITmedia NEWS
- 2023 年は GitHub から 1,200 万件を超える認証情報が流出|マイナビニュース
- GitHubでのトークンと暗号化キーの漏洩|カスペルスキー公式ブログ
- 事例から学ぶ、GitHub の使用に伴う危険性|Qiita
- Best practices for preventing data leaks in your organization|GitHub Docs
- gitleaks/gitleaks|GitHub
- trufflesecurity/trufflehog|GitHub
- TruffleHog vs. Gitleaks: A Detailed Comparison|Jit
- Secret Scanning in CI/CD: detect-secrets vs gitleaks vs TruffleHog|Rafter
- About mandatory two-factor authentication|GitHub Docs
Discussion
ちょっと評価が甘いかなと思います。扱っているものの性質を考えれば、履歴上に、Availableな鍵があった時点でNGです。また、5/3付けまでのリリースを見る限り一貫してエンジニア以外を煙に巻くコメントしか発表されていないのも怒りを覚えます。
技術的チェックリストとしてはとても有用。
ただし、公式発表から確認できる事実より一歩踏み込んだ断定が複数あり、今回の事案の原因分析として読む場合は、事実と推測を切り分けて読む必要がある。
特に注意すべきは以下です。
拝読しました。最近の若い方の記事はよく整理されていて、私のような古い人間にも勉強になります。
ただ一点だけ、老婆心ながら申し上げますと、「GitHubの認証情報が漏れること自体は仕方ない」という書き方は、私の世代から見るとちょっと甘い気もしますな。私が現役でシステムを触っていた頃は、「鍵が漏れた」と聞けば、まず叱られるのは設計した人間でしたよ。技術が変わっても、扱っているのがお客様のお金とお名前である以上、「どこでも起こり得る」で済ませてはいけない場面はあると思うのです。
それから、本番のお客様データが開発のリポジトリに入っていた、という部分。これは技術の話というより、現場の規律の話ですな。私の頃は、本番データを開発機に持ち出した時点で始末書ものでした。ツールで防ぐのも結構ですが、結局のところ「触ってはいけないものは触らない」という当たり前を、若い方々にどう伝えるかが、上の人間の仕事ではないかと感じております。
長くなって失礼しました。良い記事をありがとうございました。