[{"data":1,"prerenderedAt":1674},["ShallowReactive",2],{"content-/moneyforward-leak-lessons":3,"all-pages-for-dir":1672,"og-image-/moneyforward-leak-lessons":1673},{"id":4,"title":5,"body":6,"category":1653,"description":1654,"extension":1655,"meta":1656,"navigation":471,"ogImage":1657,"path":1658,"project_name":1659,"published":1660,"publishedAt":1661,"seo":1662,"stem":1663,"tags":1664,"todo":1670,"unpublished":1660,"updatedAt":1657,"__hash__":1671},"pages/2026-05/2026-05-02/moneyforward-leak-lessons.md","マネーフォワードGitHub流出を受けて、ひとり開発の秘密管理を棚卸しした",{"type":7,"value":8,"toc":1629},"minimark",[9,13,25,28,31,34,37,89,92,95,98,133,136,139,144,227,230,296,300,303,381,384,391,414,418,451,454,457,460,540,544,549,617,621,712,716,808,812,850,853,856,860,954,963,967,1289,1293,1299,1457,1481,1485,1574,1580,1584,1591,1613,1616,1619,1622,1625],[10,11,12],"h2",{"id":12},"きっかけ",[14,15,16,17,24],"p",{},"2026年5月1日に公表された",[18,19,23],"a",{"href":20,"rel":21},"https://zenn.dev/awesome_kou/articles/moneyforward-github-source-leak",[22],"nofollow","マネーフォワードのGitHub不正アクセス事件","を読んだ。ソースコード一式・カード保持者370件分の氏名と下4桁・各種認証キーが流出した、というインシデントである。",[14,26,27],{},"記事の主旨はシンプルで、「認証情報の漏えい自体は防ぎきれない。だが、漏れたあとに被害がどこまで広がるかは、平時の設計でほぼ決まる」というもの。",[14,29,30],{},"自分のリポジトリは個人プロジェクトなので規模も影響範囲も違う。とはいえ、ブログ・財務データ閲覧・Cloudflareへの自動デプロイ・Claude Codeとの連携など、認証情報を扱う場面は意外に多い。「いま流出したら何が起きるか」を一度棚卸ししておきたい、と思った。",[14,32,33],{},"この記事は、対策を網羅的に並べた上で、自分のリポジトリで「やっていない・足りない」ものをチェックリスト化したものだ。同じ規模の個人開発者の参考になれば。",[10,35,36],{"id":36},"起きたことの要約",[38,39,40,53],"table",{},[41,42,43],"thead",{},[44,45,46,50],"tr",{},[47,48,49],"th",{},"項目",[47,51,52],{},"内容",[54,55,56,65,73,81],"tbody",{},[44,57,58,62],{},[59,60,61],"td",{},"公表日",[59,63,64],{},"2026年5月1日",[44,66,67,70],{},[59,68,69],{},"流出物",[59,71,72],{},"ソースコード一式、カード保持者370件分の氏名(ローマ字)とカード番号下4桁、各種認証キー・パスワード",[44,74,75,78],{},[59,76,77],{},"流出していないもの",[59,79,80],{},"カード番号全桁、有効期限、CVV、本番DB情報",[44,82,83,86],{},[59,84,85],{},"対応",[59,87,88],{},"認証情報無効化・鍵の一括ローテーション・銀行連携機能の一時停止",[14,90,91],{},"GitHub認証情報の漏えい経路として一般的に多いのは、開発者PCのマルウェア感染、公開リポジトリへの誤コミット、サードパーティ連携の侵害、フィッシングの4つ。今回の経路は公表されていないが、事後対応から見ても「鍵がコミットに含まれていた／環境変数管理が甘かった」状況は推測できる。",[10,93,94],{"id":94},"元記事が推奨している対策セット",[14,96,97],{},"元記事では以下のセットを推している。これは業界標準の構成で、自分の環境にも基本そのまま当てはまる。",[99,100,101,109,115,121,127],"ul",{},[102,103,104,108],"li",{},[105,106,107],"strong",{},"秘密検出",": gitleaksをpre-commitとCIに、TruffleHogで過去履歴を定期スイープ、GitHub標準のSecret Scanning + Push Protection有効化",[102,110,111,114],{},[105,112,113],{},"履歴クリーンアップ",": 検出された鍵は即時失効が最優先、git-filter-repoで履歴削除、全メンバー再クローン",[102,116,117,120],{},[105,118,119],{},"本番データ取扱",": Faker/Mimesis等で合成データ生成、不可逆な仮名化・マスキングを必須化、本番データのリポジトリ持ち込み禁止",[102,122,123,126],{},[105,124,125],{},"秘密管理サービス",": AWS Secrets Manager / SSM / GCP Secret Manager / Vault等への移行、環境別の鍵分離、有効期限と自動ローテーション、アクセス監査",[102,128,129,132],{},[105,130,131],{},"認証方式刷新",": PAT廃止、GitHub Appの短期トークン、CI/CDはOIDC、残るPATはFine-grainedで権限最小化",[10,134,135],{"id":135},"元記事に書かれていないけど追加で入れたい対策",[14,137,138],{},"ひとり開発・小規模開発の文脈で、元記事の射程に入っていないが効果が高いと感じたものを足す。",[140,141,143],"h3",{"id":142},"githubの設定でいま無料で押せるボタン","GitHubの設定でいま無料で押せるボタン",[99,145,146,152,158,164,170,176,182,188,194,209,215,221],{},[102,147,148,151],{},[105,149,150],{},"Secret Scanning",": 公開リポジトリは標準で有効。private/internalもPush Protection含めて有効化（Settings → Code security）",[102,153,154,157],{},[105,155,156],{},"Push Protection (リポジトリ + ユーザーアカウント両方)",": Settings → Code security → Push protection。これが一番効く。コミット段階で押し戻される",[102,159,160,163],{},[105,161,162],{},"Dependabot Alerts + Security Updates + Version Updates",": 既知脆弱性のあるパッケージを自動でPR化",[102,165,166,169],{},[105,167,168],{},"CodeQL Default Setup",": 個人リポジトリは無料。Settings → Code security → Code scanning → Set up",[102,171,172,175],{},[105,173,174],{},"Branch Protection / Ruleset",": masterへの直push禁止、必須レビュー（個人なら自己レビューでもよい）、Force Push禁止、署名コミット必須、線形履歴",[102,177,178,181],{},[105,179,180],{},"Required commit signing (GPG/SSH/Sigstore)",": なりすましコミット防止",[102,183,184,187],{},[105,185,186],{},"2FA強制 + Passkey",": 個人アカウント設定。Organization化しているなら全メンバー強制",[102,189,190,193],{},[105,191,192],{},"GitHub Apps化 / OIDC化",": Cloudflare、AWS、GCP等のCI連携はPATをやめてOIDC連合認証に。CloudflareもOIDC対応済",[102,195,196,199,200,204,205,208],{},[105,197,198],{},"GitHub Actionsの3rdパーティアクションのSHAピン留め",": ",[201,202,203],"code",{},"uses: actions/checkout@v4"," ではなく ",[201,206,207],{},"@\u003Ccommit-sha>","。タグは差し替え可能なので",[102,210,211,214],{},[105,212,213],{},"Workflow permissions のデフォルトを read のみに",": Settings → Actions → General → Workflow permissions",[102,216,217,220],{},[105,218,219],{},"fork PRからのsecrets読み出し禁止",": Actionsのデフォルト設定で",[102,222,223,226],{},[105,224,225],{},"Audit Log Streaming"," (Org+Enterpriseのみ): SIEMに飛ばす",[140,228,229],{"id":229},"ローカル開発側で入れたい層",[99,231,232,238,244,250,256,265,279,287],{},[102,233,234,237],{},[105,235,236],{},"husky + lint-staged + gitleaks pre-commit",": コミット前に確実に止める層。CIでの検出は遅すぎる",[102,239,240,243],{},[105,241,242],{},"detect-secrets",": 既知のシークレットパターンをベースライン化して継続監視",[102,245,246,249],{},[105,247,248],{},"eslint-plugin-no-secrets",": JS/TSコード中の長文字列リテラルを検出",[102,251,252,255],{},[105,253,254],{},"commit-msg hookでConventional Commits + 検証",": コミットメッセージへの誤貼り付け防止",[102,257,258,199,261,264],{},[105,259,260],{},"direnv / dotenvx",[201,262,263],{},".env"," をコミットに含めずにローカルで使い回す。dotenvxは暗号化での保管も可能",[102,266,267,270,271,274,275,278],{},[105,268,269],{},"Wrangler secret put"," （Cloudflare）: Wranglerのプロジェクトでは ",[201,272,273],{},"wrangler secret put"," を使い、",[201,276,277],{},".dev.vars"," はgitignore。本番環境変数はダッシュボード/CIに置く",[102,280,281,199,284],{},[105,282,283],{},"コミット署名",[201,285,286],{},"git config --global commit.gpgsign true",[102,288,289,199,292,295],{},[105,290,291],{},"ghoコマンドラインのスコープ最小化",[201,293,294],{},"gh auth login"," で取るスコープを必要分のみ",[140,297,299],{"id":298},"claude-code固有でできること","Claude Code固有でできること",[14,301,302],{},"ここは元記事のスコープ外だが、AIエージェント時代に入った今、agent経由の意図せぬ情報露出を防ぐ層は重要度が上がっている。",[99,304,305,314,333,339,357,363,369,375],{},[102,306,307,313],{},[105,308,309,310,312],{},"CLAUDE.mdに ",[201,311,263],{}," 読み取り禁止ルールを書く",": 既に自分のglobal CLAUDE.mdには入っている。プロジェクトCLAUDE.mdにも明示",[102,315,316,199,319,322,323,322,326,322,329,332],{},[105,317,318],{},"PreToolUse hookでBashコマンドを検査",[201,320,321],{},"cat .env","、",[201,324,325],{},"env",[201,327,328],{},"printenv",[201,330,331],{},"grep -r .env"," などをブロック。settings.json で hook を設定",[102,334,335,338],{},[105,336,337],{},"PreToolUse hookでgit commit前にgitleaks実行",": コミットコマンドを検知したら gitleaks protect --staged を強制",[102,340,341,348,349,352,353,356],{},[105,342,343,344,347],{},"permissionsでReadを ",[201,345,346],{},".env*"," 拒否",": settings.json の ",[201,350,351],{},"permissions.deny"," に ",[201,354,355],{},"Read(./apps/web/.env*)"," を入れる",[102,358,359,362],{},[105,360,361],{},"Subagentに権限を渡しすぎない",": サブエージェント定義の Tools 欄で機密ファイルを触る必要のないものは Read を外す",[102,364,365,368],{},[105,366,367],{},"MCPサーバーのトークンスコープ確認",": gh、freee、google-workspace等のMCPはそれぞれ強い権限を持つ。不要なトークンは無効化",[102,370,371,374],{},[105,372,373],{},"Claude Codeセッションログのローテーション",": トランスクリプトに鍵を貼ってしまった場合に備えて、定期的に削除（session-backup スキルが該当）",[102,376,377,380],{},[105,378,379],{},"Plan ModeをデフォルトON",": 危険操作前に必ず人間が見る運用",[140,382,383],{"id":383},"本番データの扱い",[14,385,386,387,390],{},"個人ブログレベルだと該当しないが、財務データを表示する画面（",[201,388,389],{},"apps/web/app/pages/","配下）など、本番由来のシードを使っている場所は要注意。",[99,392,393,399,408],{},[102,394,395,398],{},[105,396,397],{},"シードデータはFakerで生成して固定seedで再現",": テスト時に本番由来の数値を流用しない",[102,400,401,199,404,407],{},[105,402,403],{},"D1のローカル開発DBを本番から取らない",[201,405,406],{},"wrangler d1 export"," した本番ダンプはローカルで開かない、もしくは仮名化スクリプトを通す",[102,409,410,413],{},[105,411,412],{},"PII（個人情報・本人確認情報）はそもそも持たない",": 持たなければ流出もしない。最強の対策",[140,415,417],{"id":416},"物理層端末層","物理層・端末層",[99,419,420,426,432,440,445],{},[102,421,422,425],{},[105,423,424],{},"OSフルディスク暗号化"," (BitLocker / FileVault)",[102,427,428,431],{},[105,429,430],{},"EDR/MDR"," (Defender for Business、CrowdStrike等)。マルウェア経由の漏えいが一番多い経路なので",[102,433,434],{},[105,435,436,439],{},[201,437,438],{},"gh auth status"," で生きているトークンを定期棚卸し",[102,441,442],{},[105,443,444],{},"macOS Keychain / Windows Credential Manager から古いトークンを削除",[102,446,447,450],{},[105,448,449],{},"使っていないGitHub Personal Access Tokenを失効",": github.com → Settings → Developer settings → Personal access tokens",[10,452,453],{"id":453},"自分のリポジトリの現状と差分",[14,455,456],{},"ここからは mdx-playground の棚卸し。「やっている」「やっていない」を正直に書く。",[140,458,459],{"id":459},"やっていること",[99,461,464,484,494,503,511,521,527],{"className":462},[463],"contains-task-list",[102,465,468,473,474,473,476,479,480,483],{"className":466},[467],"task-list-item",[469,470],"input",{"checked":471,"disabled":471,"type":472},true,"checkbox"," ",[201,475,263],{},[201,477,478],{},".env.*"," は ",[201,481,482],{},".gitignore"," 済",[102,485,487,473,489,491,492,483],{"className":486},[467],[469,488],{"checked":471,"disabled":471,"type":472},[201,490,277],{}," (Wrangler) も ",[201,493,482],{},[102,495,497,499,500,502],{"className":496},[467],[469,498],{"checked":471,"disabled":471,"type":472}," グローバルCLAUDE.mdに ",[201,501,263],{}," 読み取り禁止ルール",[102,504,506,508,509,502],{"className":505},[467],[469,507],{"checked":471,"disabled":471,"type":472}," プロジェクトCLAUDE.mdにも ",[201,510,263],{},[102,512,514,516,517,520],{"className":513},[467],[469,515],{"checked":471,"disabled":471,"type":472}," CI/CDで使う鍵は ",[201,518,519],{},"secrets.*"," 経由（Cloudflare API Token、OG_SECRET、Claude Code OAuth）",[102,522,524,526],{"className":523},[467],[469,525],{"checked":471,"disabled":471,"type":472}," 自動デプロイは無効化済（手動トリガーのみ、SSGメモリ問題対策と副次的にrelease coordinationの安全側にも寄与）",[102,528,530,532,533,536,537,539],{"className":529},[467],[469,531],{"checked":471,"disabled":471,"type":472}," 公開記事用ディレクトリと内部メモ用ディレクトリ（",[201,534,535],{},"internal/","）が ",[201,538,482],{}," ではないが分離済（公開可否が明示）",[140,541,543],{"id":542},"抜けていること優先度順","抜けていること（優先度順）",[545,546,548],"h4",{"id":547},"p0今日中に入れたい","P0：今日中に入れたい",[99,550,552,561,570,582,591,600,609],{"className":551},[463],[102,553,555,473,557,560],{"className":554},[467],[469,556],{"disabled":471,"type":472},[105,558,559],{},"GitHub Push Protectionの有効化確認",": Settings → Code security → Secret scanning → Push protection",[102,562,564,473,566,569],{"className":563},[467],[469,565],{"disabled":471,"type":472},[105,567,568],{},"GitHub Secret Scanningの履歴チェック",": 過去のpushに既知シークレットが残っていないか",[102,571,573,473,575,199,578,581],{"className":572},[467],[469,574],{"disabled":471,"type":472},[105,576,577],{},"gitleaksでローカル全履歴スキャン",[201,579,580],{},"gitleaks detect --source . --log-opts=\"--all\""," を一度通す",[102,583,585,473,587,590],{"className":584},[467],[469,586],{"disabled":471,"type":472},[105,588,589],{},"TruffleHogで全履歴スキャン",": 検証付きの方が確実",[102,592,594,473,596,599],{"className":593},[467],[469,595],{"disabled":471,"type":472},[105,597,598],{},"過去のCloudflare API Tokenの棚卸し",": 使っていないトークンの失効",[102,601,603,473,605,608],{"className":602},[467],[469,604],{"disabled":471,"type":472},[105,606,607],{},"GitHub Personal Access Tokenの棚卸し",": 使っていないPATの失効",[102,610,612,473,614],{"className":611},[467],[469,613],{"disabled":471,"type":472},[105,615,616],{},"2FA / Passkey設定の確認",[545,618,620],{"id":619},"p11週間以内に入れたい","P1：1週間以内に入れたい",[99,622,624,633,642,650,658,666,674,694,703],{"className":623},[463],[102,625,627,473,629,632],{"className":626},[467],[469,628],{"disabled":471,"type":472},[105,630,631],{},"husky + lint-staged + gitleaks pre-commit hook",": コミット段階での防御",[102,634,636,473,638,641],{"className":635},[467],[469,637],{"disabled":471,"type":472},[105,639,640],{},"gitleaksをCI（GitHub Actions）に追加",": PR時にスキャン",[102,643,645,473,647],{"className":644},[467],[469,646],{"disabled":471,"type":472},[105,648,649],{},"Dependabot Alerts / Security Updates / Version Updates 有効化",[102,651,653,473,655,657],{"className":652},[467],[469,654],{"disabled":471,"type":472},[105,656,168],{},": 個人リポは無料",[102,659,661,473,663,665],{"className":660},[467],[469,662],{"disabled":471,"type":472},[105,664,174],{},": masterへの直push制限・force push禁止",[102,667,669,473,671],{"className":668},[467],[469,670],{"disabled":471,"type":472},[105,672,673],{},"Workflow permissions を read のみに",[102,675,677,473,679,199,682,322,685,322,688,322,691],{"className":676},[467],[469,678],{"disabled":471,"type":472},[105,680,681],{},"GitHub Actionsの3rdパーティアクションをSHAピン留め",[201,683,684],{},"actions/checkout",[201,686,687],{},"pnpm/action-setup",[201,689,690],{},"actions/setup-node",[201,692,693],{},"anthropics/claude-code-action",[102,695,697,473,699,702],{"className":696},[467],[469,698],{"disabled":471,"type":472},[105,700,701],{},"Cloudflare APIトークンを最小権限・有効期限付きに",": 現在はAccount全体権限の可能性あり、Pages:Edit と Workers Scripts:Edit に絞る",[102,704,706,473,708,711],{"className":705},[467],[469,707],{"disabled":471,"type":472},[105,709,710],{},"commit signing 有効化",": GPG or SSH",[545,713,715],{"id":714},"p2余裕ができたら入れたい","P2：余裕ができたら入れたい",[99,717,719,735,744,756,765,773,782,791,800],{"className":718},[463],[102,720,722,473,724,199,727,729,730,322,732,734],{"className":721},[467],[469,723],{"disabled":471,"type":472},[105,725,726],{},"Claude Code PreToolUse hookでBashの危険コマンドブロック",[201,728,321],{},"系、",[201,731,325],{},[201,733,328],{},"を防ぐ",[102,736,738,473,740,743],{"className":737},[467],[469,739],{"disabled":471,"type":472},[105,741,742],{},"Claude Code PreToolUse hookでgit commit前にgitleaks強制",": コミット直前にもう一段",[102,745,747,473,749,755],{"className":746},[467],[469,748],{"disabled":471,"type":472},[105,750,751,752,754],{},"Claude Code permissionsで ",[201,753,346],{}," Read拒否",": 二重防御",[102,757,759,473,761,764],{"className":758},[467],[469,760],{"disabled":471,"type":472},[105,762,763],{},"eslint-plugin-no-secrets 導入",": JS/TS中のリテラル検出",[102,766,768,473,770],{"className":767},[467],[469,769],{"disabled":471,"type":472},[105,771,772],{},"detect-secrets ベースライン化",[102,774,776,473,778,781],{"className":775},[467],[469,777],{"disabled":471,"type":472},[105,779,780],{},"Cloudflare CI連携をOIDC化",": API TokenをやめてOIDC連合認証に",[102,783,785,473,787,790],{"className":784},[467],[469,786],{"disabled":471,"type":472},[105,788,789],{},"wrangler secret put運用に統一",": 環境変数をWrangler Secretに集約",[102,792,794,473,796,799],{"className":793},[467],[469,795],{"disabled":471,"type":472},[105,797,798],{},"MCPサーバーのトークン棚卸し",": freee、Google Workspace等",[102,801,803,473,805],{"className":802},[467],[469,804],{"disabled":471,"type":472},[105,806,807],{},"Claude Codeセッションログの定期ローテーション",[545,809,811],{"id":810},"p3やらないオーバーエンジニアリングと判断","P3：やらない/オーバーエンジニアリングと判断",[99,813,815,824,832,841],{"className":814},[463],[102,816,818,473,820,823],{"className":817},[467],[469,819],{"disabled":471,"type":472},[105,821,822],{},"AWS Secrets Manager等への移行",": ひとりプロジェクトでCloudflareに完結している間は不要。Wrangler Secretで十分",[102,825,827,473,829,831],{"className":826},[467],[469,828],{"disabled":471,"type":472},[105,830,225],{},": GitHub Enterprise必須機能なので個人プランでは不可",[102,833,835,473,837,840],{"className":834},[467],[469,836],{"disabled":471,"type":472},[105,838,839],{},"EDR/MDR導入",": BYOD個人PCでは過剰。Windows Defender + 定期スキャンで運用",[102,842,844,473,846,849],{"className":843},[467],[469,845],{"disabled":471,"type":472},[105,847,848],{},"GitHub Apps化",": 個人プロジェクトではPATで十分",[10,851,852],{"id":852},"具体的な設定例",[14,854,855],{},"実装するときに見返す用のメモ。記事を書きながら検証していないので、導入時には公式ドキュメントを当たること。",[140,857,859],{"id":858},"gitleaks-pre-commit-hook","gitleaks pre-commit hook",[861,862,867],"pre",{"className":863,"code":864,"language":865,"meta":866,"style":866},"language-bash shiki shiki-themes vitesse-light vitesse-light","# Husky導入\npnpm add -D husky lint-staged\npnpm exec husky init\n\n# .husky/pre-commit に以下を追記\ngitleaks protect --staged --redact --verbose || exit 1\n","bash","",[201,868,869,878,899,912,918,924],{"__ignoreMap":866},[870,871,874],"span",{"class":872,"line":873},"line",1,[870,875,877],{"class":876},"sxvE3","# Husky導入\n",[870,879,881,885,889,893,896],{"class":872,"line":880},2,[870,882,884],{"class":883},"senZ8","pnpm",[870,886,888],{"class":887},"sdGka"," add",[870,890,892],{"class":891},"snbK4"," -D",[870,894,895],{"class":887}," husky",[870,897,898],{"class":887}," lint-staged\n",[870,900,902,904,907,909],{"class":872,"line":901},3,[870,903,884],{"class":883},[870,905,906],{"class":887}," exec",[870,908,895],{"class":887},[870,910,911],{"class":887}," init\n",[870,913,915],{"class":872,"line":914},4,[870,916,917],{"emptyLinePlaceholder":471},"\n",[870,919,921],{"class":872,"line":920},5,[870,922,923],{"class":876},"# .husky/pre-commit に以下を追記\n",[870,925,927,930,933,936,939,942,946,950],{"class":872,"line":926},6,[870,928,929],{"class":883},"gitleaks",[870,931,932],{"class":887}," protect",[870,934,935],{"class":891}," --staged",[870,937,938],{"class":891}," --redact",[870,940,941],{"class":891}," --verbose",[870,943,945],{"class":944},"stQ0i"," ||",[870,947,949],{"class":948},"sz8Xr"," exit",[870,951,953],{"class":952},"sM54T"," 1\n",[14,955,956,958,959,962],{},[201,957,929],{}," バイナリは Scoop / winget / brew で入る。Windowsなら ",[201,960,961],{},"scoop install gitleaks","。",[140,964,966],{"id":965},"github-actionsにgitleaksとtrufflehogを追加","GitHub ActionsにgitleaksとTruffleHogを追加",[861,968,972],{"className":969,"code":970,"language":971,"meta":866,"style":866},"language-yaml shiki shiki-themes vitesse-light vitesse-light","# .github/workflows/security.yml\nname: Security Scan\n\non:\n  pull_request:\n  push:\n    branches: [master]\n  schedule:\n    - cron: '0 0 * * 0'  # 毎週日曜\n\npermissions:\n  contents: read\n\njobs:\n  gitleaks:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@\u003Csha>  # SHAピン留め\n        with:\n          fetch-depth: 0  # 全履歴スキャン用\n      - uses: gitleaks/gitleaks-action@\u003Csha>\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n  trufflehog:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@\u003Csha>\n        with:\n          fetch-depth: 0\n      - uses: trufflesecurity/trufflehog@\u003Csha>\n        with:\n          extra_args: --only-verified\n","yaml",[201,973,974,979,991,995,1004,1011,1018,1035,1043,1067,1072,1080,1091,1096,1104,1112,1123,1131,1148,1156,1170,1182,1190,1201,1206,1214,1223,1230,1242,1249,1259,1271,1278],{"__ignoreMap":866},[870,975,976],{"class":872,"line":873},[870,977,978],{"class":876},"# .github/workflows/security.yml\n",[870,980,981,984,988],{"class":872,"line":880},[870,982,983],{"class":948},"name",[870,985,987],{"class":986},"shFtX",":",[870,989,990],{"class":887}," Security Scan\n",[870,992,993],{"class":872,"line":901},[870,994,917],{"emptyLinePlaceholder":471},[870,996,997,1001],{"class":872,"line":914},[870,998,1000],{"class":999},"sHkkW","on",[870,1002,1003],{"class":986},":\n",[870,1005,1006,1009],{"class":872,"line":920},[870,1007,1008],{"class":948},"  pull_request",[870,1010,1003],{"class":986},[870,1012,1013,1016],{"class":872,"line":926},[870,1014,1015],{"class":948},"  push",[870,1017,1003],{"class":986},[870,1019,1021,1024,1026,1029,1032],{"class":872,"line":1020},7,[870,1022,1023],{"class":948},"    branches",[870,1025,987],{"class":986},[870,1027,1028],{"class":986}," [",[870,1030,1031],{"class":887},"master",[870,1033,1034],{"class":986},"]\n",[870,1036,1038,1041],{"class":872,"line":1037},8,[870,1039,1040],{"class":948},"  schedule",[870,1042,1003],{"class":986},[870,1044,1046,1049,1052,1054,1058,1061,1064],{"class":872,"line":1045},9,[870,1047,1048],{"class":986},"    -",[870,1050,1051],{"class":948}," cron",[870,1053,987],{"class":986},[870,1055,1057],{"class":1056},"sMJiu"," '",[870,1059,1060],{"class":887},"0 0 * * 0",[870,1062,1063],{"class":1056},"'",[870,1065,1066],{"class":876},"  # 毎週日曜\n",[870,1068,1070],{"class":872,"line":1069},10,[870,1071,917],{"emptyLinePlaceholder":471},[870,1073,1075,1078],{"class":872,"line":1074},11,[870,1076,1077],{"class":948},"permissions",[870,1079,1003],{"class":986},[870,1081,1083,1086,1088],{"class":872,"line":1082},12,[870,1084,1085],{"class":948},"  contents",[870,1087,987],{"class":986},[870,1089,1090],{"class":887}," read\n",[870,1092,1094],{"class":872,"line":1093},13,[870,1095,917],{"emptyLinePlaceholder":471},[870,1097,1099,1102],{"class":872,"line":1098},14,[870,1100,1101],{"class":948},"jobs",[870,1103,1003],{"class":986},[870,1105,1107,1110],{"class":872,"line":1106},15,[870,1108,1109],{"class":948},"  gitleaks",[870,1111,1003],{"class":986},[870,1113,1115,1118,1120],{"class":872,"line":1114},16,[870,1116,1117],{"class":948},"    runs-on",[870,1119,987],{"class":986},[870,1121,1122],{"class":887}," ubuntu-latest\n",[870,1124,1126,1129],{"class":872,"line":1125},17,[870,1127,1128],{"class":948},"    steps",[870,1130,1003],{"class":986},[870,1132,1134,1137,1140,1142,1145],{"class":872,"line":1133},18,[870,1135,1136],{"class":986},"      -",[870,1138,1139],{"class":948}," uses",[870,1141,987],{"class":986},[870,1143,1144],{"class":887}," actions/checkout@\u003Csha>",[870,1146,1147],{"class":876},"  # SHAピン留め\n",[870,1149,1151,1154],{"class":872,"line":1150},19,[870,1152,1153],{"class":948},"        with",[870,1155,1003],{"class":986},[870,1157,1159,1162,1164,1167],{"class":872,"line":1158},20,[870,1160,1161],{"class":948},"          fetch-depth",[870,1163,987],{"class":986},[870,1165,1166],{"class":952}," 0",[870,1168,1169],{"class":876},"  # 全履歴スキャン用\n",[870,1171,1173,1175,1177,1179],{"class":872,"line":1172},21,[870,1174,1136],{"class":986},[870,1176,1139],{"class":948},[870,1178,987],{"class":986},[870,1180,1181],{"class":887}," gitleaks/gitleaks-action@\u003Csha>\n",[870,1183,1185,1188],{"class":872,"line":1184},22,[870,1186,1187],{"class":948},"        env",[870,1189,1003],{"class":986},[870,1191,1193,1196,1198],{"class":872,"line":1192},23,[870,1194,1195],{"class":948},"          GITHUB_TOKEN",[870,1197,987],{"class":986},[870,1199,1200],{"class":887}," ${{ secrets.GITHUB_TOKEN }}\n",[870,1202,1204],{"class":872,"line":1203},24,[870,1205,917],{"emptyLinePlaceholder":471},[870,1207,1209,1212],{"class":872,"line":1208},25,[870,1210,1211],{"class":948},"  trufflehog",[870,1213,1003],{"class":986},[870,1215,1217,1219,1221],{"class":872,"line":1216},26,[870,1218,1117],{"class":948},[870,1220,987],{"class":986},[870,1222,1122],{"class":887},[870,1224,1226,1228],{"class":872,"line":1225},27,[870,1227,1128],{"class":948},[870,1229,1003],{"class":986},[870,1231,1233,1235,1237,1239],{"class":872,"line":1232},28,[870,1234,1136],{"class":986},[870,1236,1139],{"class":948},[870,1238,987],{"class":986},[870,1240,1241],{"class":887}," actions/checkout@\u003Csha>\n",[870,1243,1245,1247],{"class":872,"line":1244},29,[870,1246,1153],{"class":948},[870,1248,1003],{"class":986},[870,1250,1252,1254,1256],{"class":872,"line":1251},30,[870,1253,1161],{"class":948},[870,1255,987],{"class":986},[870,1257,1258],{"class":952}," 0\n",[870,1260,1262,1264,1266,1268],{"class":872,"line":1261},31,[870,1263,1136],{"class":986},[870,1265,1139],{"class":948},[870,1267,987],{"class":986},[870,1269,1270],{"class":887}," trufflesecurity/trufflehog@\u003Csha>\n",[870,1272,1274,1276],{"class":872,"line":1273},32,[870,1275,1153],{"class":948},[870,1277,1003],{"class":986},[870,1279,1281,1284,1286],{"class":872,"line":1280},33,[870,1282,1283],{"class":948},"          extra_args",[870,1285,987],{"class":986},[870,1287,1288],{"class":887}," --only-verified\n",[140,1290,1292],{"id":1291},"claude-code-pretooluse-hookbashのenv読み取りブロック","Claude Code PreToolUse hook（Bashの.env読み取りブロック）",[14,1294,1295,1298],{},[201,1296,1297],{},".claude/settings.json"," に追記。",[861,1300,1304],{"className":1301,"code":1302,"language":1303,"meta":866,"style":866},"language-json shiki shiki-themes vitesse-light vitesse-light","{\n  \"hooks\": {\n    \"PreToolUse\": [\n      {\n        \"matcher\": \"Bash\",\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"node .claude/hooks/block-env-read.mjs\"\n          }\n        ]\n      }\n    ]\n  }\n}\n","json",[201,1305,1306,1311,1328,1343,1348,1371,1383,1388,1409,1427,1432,1437,1442,1447,1452],{"__ignoreMap":866},[870,1307,1308],{"class":872,"line":873},[870,1309,1310],{"class":986},"{\n",[870,1312,1313,1317,1320,1323,1325],{"class":872,"line":880},[870,1314,1316],{"class":1315},"sqvqQ","  \"",[870,1318,1319],{"class":948},"hooks",[870,1321,1322],{"class":1315},"\"",[870,1324,987],{"class":986},[870,1326,1327],{"class":986}," {\n",[870,1329,1330,1333,1336,1338,1340],{"class":872,"line":901},[870,1331,1332],{"class":1315},"    \"",[870,1334,1335],{"class":948},"PreToolUse",[870,1337,1322],{"class":1315},[870,1339,987],{"class":986},[870,1341,1342],{"class":986}," [\n",[870,1344,1345],{"class":872,"line":914},[870,1346,1347],{"class":986},"      {\n",[870,1349,1350,1353,1356,1358,1360,1363,1366,1368],{"class":872,"line":920},[870,1351,1352],{"class":1315},"        \"",[870,1354,1355],{"class":948},"matcher",[870,1357,1322],{"class":1315},[870,1359,987],{"class":986},[870,1361,1362],{"class":1056}," \"",[870,1364,1365],{"class":887},"Bash",[870,1367,1322],{"class":1056},[870,1369,1370],{"class":986},",\n",[870,1372,1373,1375,1377,1379,1381],{"class":872,"line":926},[870,1374,1352],{"class":1315},[870,1376,1319],{"class":948},[870,1378,1322],{"class":1315},[870,1380,987],{"class":986},[870,1382,1342],{"class":986},[870,1384,1385],{"class":872,"line":1020},[870,1386,1387],{"class":986},"          {\n",[870,1389,1390,1393,1396,1398,1400,1402,1405,1407],{"class":872,"line":1037},[870,1391,1392],{"class":1315},"            \"",[870,1394,1395],{"class":948},"type",[870,1397,1322],{"class":1315},[870,1399,987],{"class":986},[870,1401,1362],{"class":1056},[870,1403,1404],{"class":887},"command",[870,1406,1322],{"class":1056},[870,1408,1370],{"class":986},[870,1410,1411,1413,1415,1417,1419,1421,1424],{"class":872,"line":1045},[870,1412,1392],{"class":1315},[870,1414,1404],{"class":948},[870,1416,1322],{"class":1315},[870,1418,987],{"class":986},[870,1420,1362],{"class":1056},[870,1422,1423],{"class":887},"node .claude/hooks/block-env-read.mjs",[870,1425,1426],{"class":1056},"\"\n",[870,1428,1429],{"class":872,"line":1069},[870,1430,1431],{"class":986},"          }\n",[870,1433,1434],{"class":872,"line":1074},[870,1435,1436],{"class":986},"        ]\n",[870,1438,1439],{"class":872,"line":1082},[870,1440,1441],{"class":986},"      }\n",[870,1443,1444],{"class":872,"line":1093},[870,1445,1446],{"class":986},"    ]\n",[870,1448,1449],{"class":872,"line":1098},[870,1450,1451],{"class":986},"  }\n",[870,1453,1454],{"class":872,"line":1106},[870,1455,1456],{"class":986},"}\n",[14,1458,1459,1462,1463,1466,1467,322,1469,322,1472,322,1474,322,1477,1480],{},[201,1460,1461],{},".claude/hooks/block-env-read.mjs"," で stdin の ",[201,1464,1465],{},"tool_input.command"," を見て、",[201,1468,321],{},[201,1470,1471],{},"env\\b",[201,1473,328],{},[201,1475,1476],{},"grep -r.*\\.env",[201,1478,1479],{},"Get-Content .env"," 等のパターンに該当したら exit 2 で deny。",[140,1482,1484],{"id":1483},"claude-code-read拒否","Claude Code Read拒否",[861,1486,1488],{"className":1301,"code":1487,"language":1303,"meta":866,"style":866},"{\n  \"permissions\": {\n    \"deny\": [\n      \"Read(./apps/web/.env)\",\n      \"Read(./apps/web/.env.*)\",\n      \"Read(./.env)\",\n      \"Read(./.env.*)\"\n    ]\n  }\n}\n",[201,1489,1490,1494,1506,1519,1531,1542,1553,1562,1566,1570],{"__ignoreMap":866},[870,1491,1492],{"class":872,"line":873},[870,1493,1310],{"class":986},[870,1495,1496,1498,1500,1502,1504],{"class":872,"line":880},[870,1497,1316],{"class":1315},[870,1499,1077],{"class":948},[870,1501,1322],{"class":1315},[870,1503,987],{"class":986},[870,1505,1327],{"class":986},[870,1507,1508,1510,1513,1515,1517],{"class":872,"line":901},[870,1509,1332],{"class":1315},[870,1511,1512],{"class":948},"deny",[870,1514,1322],{"class":1315},[870,1516,987],{"class":986},[870,1518,1342],{"class":986},[870,1520,1521,1524,1527,1529],{"class":872,"line":914},[870,1522,1523],{"class":1056},"      \"",[870,1525,1526],{"class":887},"Read(./apps/web/.env)",[870,1528,1322],{"class":1056},[870,1530,1370],{"class":986},[870,1532,1533,1535,1538,1540],{"class":872,"line":920},[870,1534,1523],{"class":1056},[870,1536,1537],{"class":887},"Read(./apps/web/.env.*)",[870,1539,1322],{"class":1056},[870,1541,1370],{"class":986},[870,1543,1544,1546,1549,1551],{"class":872,"line":926},[870,1545,1523],{"class":1056},[870,1547,1548],{"class":887},"Read(./.env)",[870,1550,1322],{"class":1056},[870,1552,1370],{"class":986},[870,1554,1555,1557,1560],{"class":872,"line":1020},[870,1556,1523],{"class":1056},[870,1558,1559],{"class":887},"Read(./.env.*)",[870,1561,1426],{"class":1056},[870,1563,1564],{"class":872,"line":1037},[870,1565,1446],{"class":986},[870,1567,1568],{"class":872,"line":1045},[870,1569,1451],{"class":986},[870,1571,1572],{"class":872,"line":1069},[870,1573,1456],{"class":986},[14,1575,1576,1579],{},[201,1577,1578],{},".env.example"," は許可したいので glob ではなく明示列挙が安全。",[140,1581,1583],{"id":1582},"cloudflareトークンの最小権限化","Cloudflareトークンの最小権限化",[14,1585,1586,1587,1590],{},"現在のworkflowsで使っている ",[201,1588,1589],{},"CLOUDFLARE_API_TOKEN"," は Account全体権限の可能性が高い。dashboard → My Profile → API Tokens で以下スコープに絞る:",[99,1592,1593,1602,1610],{},[102,1594,1595,1598,1599],{},[201,1596,1597],{},"Account"," → ",[201,1600,1601],{},"Cloudflare Pages:Edit",[102,1603,1604,1598,1606,1609],{},[201,1605,1597],{},[201,1607,1608],{},"Workers Scripts:Edit","（OG Worker用）",[102,1611,1612],{},"IP制限はGitHub Actionsの動的IPなので不可、有効期限を90日等に",[10,1614,1615],{"id":1615},"まとめ",[14,1617,1618],{},"「漏れない設計」より「漏れても被害が広がらない設計」のほうが現実的、というのが元記事の核。これは個人開発でも同じで、いま自分のリポジトリで一番抜けているのは「pre-commit/CIでの自動検出層」と「鍵の棚卸し」だった。",[14,1620,1621],{},"優先度P0の項目（GitHub Push Protection確認、gitleaks/TruffleHogでの履歴スキャン、Cloudflare/PATの棚卸し）は今日中に手を動かす。P1のhusky+gitleaksはこの週内、P2のClaude Code Hookは余裕ができたら順次入れる。",[14,1623,1624],{},"「まだやれていないことを可視化する」という意味で、この記事自体が一番役に立った。",[1626,1627,1628],"style",{},"html pre.shiki code .sxvE3, html code.shiki .sxvE3{--shiki-default:#A0ADA0;--shiki-dark:#A0ADA0}html pre.shiki code .senZ8, html code.shiki .senZ8{--shiki-default:#59873A;--shiki-dark:#59873A}html pre.shiki code .sdGka, html code.shiki .sdGka{--shiki-default:#B56959;--shiki-dark:#B56959}html pre.shiki code .snbK4, html code.shiki .snbK4{--shiki-default:#A65E2B;--shiki-dark:#A65E2B}html pre.shiki code .stQ0i, html code.shiki .stQ0i{--shiki-default:#AB5959;--shiki-dark:#AB5959}html pre.shiki code .sz8Xr, html code.shiki .sz8Xr{--shiki-default:#998418;--shiki-dark:#998418}html pre.shiki code .sM54T, html code.shiki .sM54T{--shiki-default:#2F798A;--shiki-dark:#2F798A}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .shFtX, html code.shiki .shFtX{--shiki-default:#999999;--shiki-dark:#999999}html pre.shiki code .sHkkW, html code.shiki .sHkkW{--shiki-default:#1E754F;--shiki-dark:#1E754F}html pre.shiki code .sMJiu, html code.shiki .sMJiu{--shiki-default:#B5695977;--shiki-dark:#B5695977}html pre.shiki code .sqvqQ, html code.shiki .sqvqQ{--shiki-default:#99841877;--shiki-dark:#99841877}",{"title":866,"searchDepth":880,"depth":880,"links":1630},[1631,1632,1633,1634,1641,1645,1652],{"id":12,"depth":880,"text":12},{"id":36,"depth":880,"text":36},{"id":94,"depth":880,"text":94},{"id":135,"depth":880,"text":135,"children":1635},[1636,1637,1638,1639,1640],{"id":142,"depth":901,"text":143},{"id":229,"depth":901,"text":229},{"id":298,"depth":901,"text":299},{"id":383,"depth":901,"text":383},{"id":416,"depth":901,"text":417},{"id":453,"depth":880,"text":453,"children":1642},[1643,1644],{"id":459,"depth":901,"text":459},{"id":542,"depth":901,"text":543},{"id":852,"depth":880,"text":852,"children":1646},[1647,1648,1649,1650,1651],{"id":858,"depth":901,"text":859},{"id":965,"depth":901,"text":966},{"id":1291,"depth":901,"text":1292},{"id":1483,"depth":901,"text":1484},{"id":1582,"depth":901,"text":1583},{"id":1615,"depth":880,"text":1615},"dev","MFのソースコード流出事件をきっかけに、自分のリポジトリで何が抜けているかを点検する。gitleaks・GitHub Push Protection・OIDC・Claude Code Hookまで、ひとりでもいま入れられる対策を網羅的に整理した。","md",{},null,"/moneyforward-leak-lessons","mdx-playground",false,"2026-05-02T00:00:00.000Z",{"title":5,"description":1654},"2026-05/2026-05-02/moneyforward-leak-lessons",[1665,1666,1667,1668,1669,929],"security","github","claude-code","secret-management","devops","active","MijK5Q3nTxVRGtVSutfYWZ-mSsqf38bwWLI0_WinMHM",[],"https://log.eurekapu.com/og/blog/moneyforward-leak-lessons.png?v=2026-05-02T00%3A00%3A00.000Z&title=%E3%83%9E%E3%83%8D%E3%83%BC%E3%83%95%E3%82%A9%E3%83%AF%E3%83%BC%E3%83%89GitHub%E6%B5%81%E5%87%BA%E3%82%92%E5%8F%97%E3%81%91%E3%81%A6%E3%80%81%E3%81%B2%E3%81%A8%E3%82%8A%E9%96%8B%E7%99%BA%E3%81%AE%E7%A7%98%E5%AF%86%E7%AE%A1%E7%90%86%E3%82%92%E6%A3%9A%E5%8D%B8%E3%81%97%E3%81%97%E3%81%9F&author=Kei%20Komatsu&sig=2e76e30a87e7754a",1782528832057]