Claude Code に「このリポジトリをコミットして push しておいて」と任せた時、頭をよぎる不安がある。プロジェクトの .env、うっかり置いてある credentials.json、~/.ssh の鍵——こうした秘密のファイルまで、まとめてコミットされて公開リポジトリへ push されないか。
結論を先に書く。これは仮の話ではなく、実際に起きたという報告がある。そして、指示書に「コミットするな」と書くだけでは止まらない。止めたいなら、実行の一つ手前で、走ろうとしているコマンドそのものを見て拒否する仕組みが要る。以下は、その仕組みが本当に止まるのかを、自分の環境で終了コードを実測して確かめた記録だ。
まず、これは実際に起きている(伝聞)
起票 #2142(OPEN)は、深刻度を CRITICAL として、次のように報告している。CLAUDE.md に「🚨 NEVER COMMIT API KEYS TO VERSION CONTROL(API キーを絶対にバージョン管理へコミットするな)」と明記し、利用者が「その CLAUDE.md を読んでから作業して」と頼んだにもかかわらず、アシスタントが本番の API キーと認証情報を、繰り返し公開の GitHub リポジトリへコミットした、というものだ。同じセッションの中で何度も再発したとも述べられている。
つまり、恐れているとおりのことは、条件が揃えば現に起こり得る。ここで大事なのは「なぜ指示では止まらなかったのか」だ。
なぜ「CLAUDE.md に書く」だけでは止まらないのか
起票 #34132 が指摘するとおり、CLAUDE.md や .claude/rules/ に書いたルールは、あくまで助言であって、強制する仕組みではないという報告がある。モデルはそれを読むが、読んだうえで従わないことがある。#2142 はまさにその実例だ。
だとすれば、守りを「モデルが読むかもしれない文章」の側に置いても、素通りされる時は素通りされる。守りは、モデルの気分に依存しない場所——実際にコマンドが走る一つ手前——に置くしかない。Claude Code の PreToolUse フックは、Bash でコマンドが実行される直前に割り込み、そのコマンド文字列を見て、危なければ終了コード 2 を返して実行そのものを止められる。文章の指示と違い、これは無視されない。
一次検証:実行層で本当に止まるのか、自分の環境で実測した
私が配っている無料のフック集 cc-safe-setup には、この用途の中核フック secret-guard が入っている。中身を読むだけでは信用できないので、秘密を漏らす形のコマンドを実際にフックへ渡し、手元の使い捨て git リポジトリで実走して終了コードを実測した(2 = 実行の手前でブロック、0 = そのまま通す)。フックには {"tool_input":{"command":"..."}} を標準入力から渡している。
止まってほしい形は、自分の環境ですべて exit 2 でブロックされることを再現できた。
| 与えたコマンド | 終了コード |
|---|---|
git add .env |
2(ブロック) |
git add config/.env(サブディレクトリ) |
2 |
git add -f .env(.gitignore を無視する強制追加) |
2 |
git add credentials.json |
2 |
git add ~/.ssh/id_rsa |
2 |
git add server.pem |
2 |
echo done && git add .env(連結コマンド) |
2 |
git add -A(同じ場所に .env がある時) |
2 |
注目したいのは、いちばん下の git add -A だ。エージェントが最も自然に打つのは、個別のファイル名を選ぶことではなく、git add -A && git commit -m ... のように「全部まとめて」の形だ。#2142 の漏洩も、この「全部まとめて」の系統で起きやすい。その最も危ない形が、.env の存在を見て実行の手前で止まる。連結(&&)の後ろに隠しても止まる点も、自分で確かめた。
正直な限界:フックは一枚の層であって、保証ではない
同じ実測で、素通りする形(exit 0)も測った。ここを隠すのは不誠実なので、そのまま書く。守りを過信しないための、いちばん大事な部分だ。
| 与えたコマンド | 終了コード | なぜ素通りするか |
|---|---|---|
git commit -m wip |
0 | このフックが見るのは git add の段。すでにステージ済みの秘密は commit / push の段では検査しない |
git push origin main |
0 | 同上。push そのものは見ていない |
git add .npmrc |
0 |
.npmrc は認証トークンを持つが、名前がパターンに無い |
git add secrets.yaml |
0 | 別名の秘密ファイルは名前で捕まらない |
git add config.json(中身が API キー) |
0 | フックはコマンド文字列を見る。ファイルの中身は見ない |
自分の環境での実測から読み取れることは、はっきりしている。このフックは、いちばん起きやすい漏洩の形(git add .env と git add -A)を実行の手前で確実に止める。しかし、漏洩を不可能にはしない。別の名前の秘密ファイル、無害な名前のファイルに貼った秘密、すでにステージされたものは、この一枚では防ぎきれない。
だからフックは一枚の層として使い、次の運用と組み合わせるのが現実的だ。
- 秘密ファイルは必ず
.gitignoreに入れる(フックはその手前の最後の網)。 -
git add -Aを癖にせず、git add src/ package.jsonのように触ったファイルを明示的に指定する。 - 生きた秘密を、追跡対象のファイル(
config.jsonなど)に直接書かない。
まとめ
「CLAUDE.md に書いたのに守られない」と「実行の手前で本当に止まる」の差は、守りをどこに置くかの差だ。#2142 は前者の限界を、自分の環境での実測は後者の効き方とその限界を示している。指示は無視され得るが、終了コード 2 は無視されない。
手元で今すぐ試せる守り(無料)
上の secret-guard は、cc-safe-setup の中核フックとして既定で入る。
npx cc-safe-setup
導入すると、git add .env や .env がある状態の git add -A が、実行の手前で止まる。中身と検証手順は GitHub に公開している。→ https://github.com/yurukusa/cc-safe-setup
事故の全体像を体系で押さえたい方へ(¥800)
秘密の漏洩だけでなく、未コミット作業の消失、費用の暴走、停止したはずの処理の暴走など、Claude Code の運用で実際に起きた事故を、原因と手元の守りごとにまとめた事故防止本を出している(¥800)。この記事の秘密漏洩も、より深いところまで扱っている。→ https://zenn.dev/yurukusa/books/6076c23b1cb18b