0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Codeの.envガードが止めた書き方は、18のうち2つだった

0
Posted at

Claude Codeの.envガードが止めた書き方は、18のうち2つだった

Claude Code(ターミナルで動く、Anthropic のコーディング用のAI)に「コミットしてpushしておいて」と任せる場面は多い。ここで多くの利用者が抱く不安がある。プロジェクトの .env にはAPIキーが入っている。これが間違って公開リポジトリに上がることはないのか。

上がりうる。しかもこれは想像ではなく、公開の記録に実例がある。

対策としてよく挙がるのがフックだ。フックは、AIがコマンドを実行する手前に割り込んで、危ないものを機械的に弾く仕組みで、CLAUDE.md に「絶対にコミットするな」と書くのとは層が違う。私はそのフック集 cc-safe-setup を無料(MITライセンス)で公開していて、その中の secret-guard.env の混入を見る担当だ。自分が配っているものが、実際にどこまで止まるのかを終了コードで測った。答えは、18の書き方のうち2つだった。

以下は全部、2026年9月4日に自分の環境で撃った結果だ。危険なコマンドは一度も実行していない。コマンドを「文字列」としてフックの標準入力に渡し、終了コード(2なら実行の手前で停止、0なら素通り)だけを観測している。

18の書き方へ、同じ .env を渡した

読者が npx cc-safe-setup で実際に入るのは、npm が配っている 29.8.0 だ(dist-tags.latest は今も29.8.0で、公開は2026年4月20日)。GitHub 側の現行は 30.0.4 になっている。両方へ同じ入力を流した。

書き方 29.8.0 30.0.4
git add .env 2 2
先頭に空白を置く 2 2
cd myrepo && git add .env 0 2
echo hi; git add .env 0 2
git -C myrepo add .env 0 2
行末を \ で折って2行にする 0 2
(git add .env) かっこで囲む 0 0
{ git add .env; } 0 0
if true; then git add .env; fi 0 0
for f in 1; do git add .env; done 0 0
true | git add .env 0 0
echo .env | xargs git add 0 0
sh -c 'git add .env' 0 0
eval 'git add .env' 0 0
timeout 5 git add .env 0 0
nohup git add .env 0 0
GIT_DIR=x git add .env 0 0
git stage .env 0 0

止めた数は、29.8.0 が18のうち2、30.0.4 が18のうち6。現行版でも、12の書き方は素通りする。

【CC補足】なぜ抜けるのか
29.8.0 の入口は grep -qE '^\s*git\s+add' の一行だ。grep^ は「文字列の先頭」ではなく「行の先頭」を指す。だから git add が行の途中に来る書き方は、そこで全部落ちる。30.0.4 は入口を (^|;|&&|\|\|)\s*git\s+add へ広げたので、;&&|| の後ろは拾えるようになった。だが (` やパイプや eval や環境変数の前置は、この一覧に入っていない。名前と位置の字面で見る網は、書き方の空間を数えきれないので、こういう形で残る。塞がったのは名指しした形であって、族ではない。

一括の git add . は「フックが動いている場所の直下」しか見ていない

29.8.0 と 30.0.4 は、どちらも git add . のときに .env の実在を確かめる。ただし実装は [ -f ".env" ] で、これはフックのプロセスのカレントディレクトリだけを見る。よくある構成で撃つとこうなる。

状況 29.8.0 30.0.4
git add .(同じ場所に .env がある) 2 2
git add ..envbackend/ にある) 0 0
git add -A.envbackend/ にある) 0 0
git add backend/ 0 0
git commit -am "wip" 0 0
git push origin main 0 0

フロントとバックを分けていて backend/.env を持つ、ごく普通の構成は、両版とも素通りする。「一括の add は防げる」と読まないでほしい。防げるのは、フックが動いている場所の真下に .env がある場合だけだ。

commitpush が0なのは、secret-guardgit add のところだけを見る設計だからで、これは版が上がっても変わらない。ただし「原理的に無理」ではない。同じパッケージの examples/ に、コミットの直前にステージ済みの差分を見る staged-secret-scan.sh が入っている(29.8.0 の tarball にも含まれている)。既定では入らないので、足すなら明示的に入れる。

npx cc-safe-setup --install-example staged-secret-scan

push を見る柵は、いまのところ無い。

これは実際に起きている

公開の記録に、同じことで困っている報告がある。#2142 は、深刻度を CRITICAL - Active exposure of production credentials to public repositories として、CLAUDE.md に「絶対にコミットするな」と明示したのに、本番のAPIキーが公開リポジトリへ繰り返しコミットされた、という報告だ。もっと具体的なのが #12524 で、実際のAPIキーが直書きされ、The key was exposed in a public repo for 11 days、そして Hackers found it and used $30,000 USD worth of API calls とある。ただし原文には I committed and pushed without noticing ともあり、コミットとpushをしたのは報告者自身だ。AIが勝手にpushした話ではない。

ここは他人の報告なので、私が再現したわけではない。金額も日数も報告者の申告だ。ただし、この3件が今どういう状態かは自分で見た。#2142 は今も開いたままで、#12524#59094 は閉じているが、閉じ方はどちらも not_planned——直ったから閉じたのではなく、対応しないまま閉じられている(2026年9月4日にAPIで確認)。だから「もう修正済みだろう」と読まないでほしい。

#2142 が示すのは、平文の禁止が効かない場面があるということだ。CLAUDE.md に書いた禁止は、モデルへの「お願い」であって、実行を機械的に止める仕組みではない。だから致命的な操作は、言葉で頼む層ではなく、コマンドが実行される手前で機械的に弾く層で止める。上で測ったのが、その層だ。

なお #59094 は、git を通らない漏れ方の報告だ。エージェントが .env を読んで、その中身が転写へ流れた。上の表のどの行でも止まらない。secret-guard はそもそも git のコマンドしか見ていない。

本当の予防は、フックの手前にある

測って分かったのは、フックは安全網の一層であって本丸ではない、ということだ。

第一に、そもそも秘密を追跡しないこと。.gitignore.env を入れる。**.gitignore に書いたファイルは git add . でも入らない。**ここを取り違えていた人がいたら(私の以前の原稿がそうだった)、直してほしい。git add . は未追跡のファイルこそステージするので、「まだ追跡していないから安全」は成り立たない。効いているのは未追跡であることではなく、.gitignore に書いてあることのほうだ。

第二に、自分のリポで今すぐ確かめること。危ないことは何もしない。見るだけだ。

git ls-files | grep -iE '\.env|secret|credential|\.pem|\.key'

ただしこれは今のツリーしか見ない。過去に上げて、あとから git rm --cached で外した分は出てこない。履歴も見る。

git log --all --diff-filter=A --name-only --format= | sort -u | grep -iE '\.env|secret|credential|\.pem|\.key'

ここで何か出てきたら、その秘密はすでに git に入っている。次の節へ進んでほしい。

第三に、フックはその上に重ねる網として入れること。名指しの git add .env と、同じ場所に .env がある一括の add は止まる。それ以外は上の表のとおりだ。

もし、もう上げてしまっていたら——鍵の失効が先

一度公開された秘密は「もう漏れたもの」として扱うしかない。誰かがすでに clone しているかもしれないし、公開を監視して秘密を収集する自動化が、上がった瞬間に拾っている可能性もある。

だから順番はこうだ。まず、その鍵を失効させて新しい鍵を発行する。これが唯一、確実に安全にする手だ。履歴の書き換えは、そのあとの二次的な後始末にすぎない。順番を間違えて、履歴を消したことで安心し、鍵をそのままにするのが、いちばん危ない。

まとめ

  • Claude Code に git を任せると、.env やAPIキーが公開リポに上がりうる。実例が公開の記録にある
  • 私が配っている無料の secret-guard は、18の書き方のうち 29.8.0 で2つ、30.0.4 で6つを止めた。かっこ・パイプ・eval・環境変数の前置は現行でも素通りする
  • 一括の git add . で止まるのは、フックが動いている場所の直下に .env がある場合だけ。backend/.env は両版とも素通り
  • コミットの直前は examples/staged-secret-scan.sh を明示的に足せば見られる。push を見る柵は無い
  • 本丸は .gitignore。フックはその上に重ねる網
  • もう上げてしまったら、履歴の書き換えより先に鍵を失効させる

ここで測ったフック集は無料で、npx github:yurukusa/cc-safe-setup で入る。npm 側は4月から公開が止まっていて(公開は人の手でやっているので今も29.8.0)、前置と連結のすり抜けが塞がっていない。入れるなら GitHub のほうを使ってほしい。削除・費用暴走・秘密漏洩・停止不能まで、Claude Code の事故を実例で体系立てて防ぎたい人向けに、事故防止の本(¥1,500)も書いている。どちらも「絶対に安全」は約束しない。字面のガードには限界があるから、層で守るしかない——この記事はその実測だ。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?