メインコンテンツへスキップ

.envを全文AIに読ませない方が良いことを、もっと早く知りたかった話

先日、Claude Codeのターミナルがなんとなく重いな、と感じた日があった。設定まわりを棚卸ししてみたら、許可リストの中に、生のパスワードが10件、そのまま書き込まれていた。これは早めに直さないとまずいやつだ──そんな話を、今日は書こうと思う。

ターミナルが重い、と思って棚卸ししたら

Claude Codeを毎日のように使っていると、許可リストというファイルがどんどん肥大化していく。「このコマンドはこのまま実行していいよ」という許可を1個ずつ覚えてくれる仕組みで、便利な反面、気づくと数百件に膨らんでいる。中には許可の連続で、ポンポン進んでしまうこともある。

※「許可リスト」とは、Claude Codeが事前承認なしで実行できるコマンドの一覧のことです。設定ファイル(settings.json)の中に保存されていて、過去に「いつも許可」を選んだコマンドが記録されていきます。

その日、ターミナルの反応がもったりしてきた気がして、許可リストを開いてみたら465件あってじっくり見てみた。

気づき①:WordPressのアプリケーションパスワードが、生のまま、コマンド文字列に焼き付いていた
気づき②:そのままだと、設定ファイルを共有・バックアップしただけで漏れる状態
気づき③:焼き付いていた件数は、10件あった

10件のうちの1つは、ぼかすとこんな感じだった。

curl -u "user:abcd 1234 efgh 5678" https://example.com/wp-json/...

これがそのまま、設定ファイルの中に文字列として残っていた。許可リストは「過去に承認したコマンドの履歴」みたいなものなので、ここに認証情報が混ざってしまうと、あとから「やっぱりなかったことに」というのが難しい。

なぜそうなっていたのか

原因①:認証付きのコマンドを、毎回その場でClaudeに作ってもらっていた

WordPressのREST APIを叩くとき、curlに -u "user:password" の形で認証情報を渡すやり方がある。これを、毎回その場で「このサイトのREST APIから〇〇を取って」とClaudeに頼んでいた。Claudeはコマンドを組み立てて実行しようとするのだけど、その時の文字列に、生のパスワードがそのまま入る。

普通のコマンドなら、Claudeは「このコマンドを実行していい?」と聞いてくる。そこで「いつも許可」を選んでしまうと、許可リストにそのコマンドが丸ごと記録される──パスワードごと。これが10回積み重なって、10件の焼き付きになっていた。

原因②:「.envを参照していい?」に、よくわからないまま「はい」と答えていた

もう1つは、たぶんこっちが大きい。プロジェクトの.envファイル(パスワードやAPIキーをまとめておくファイル)には、認証情報がいくつも書いてある。作業の途中でClaudeから「認証に必要なので.envを参照します」と確認されることがあって、そのたびに「ああ、たしか.envにパスワード書いてあったな」と思って、そのまま許可していた。

※「.env」とは、APIキーやパスワードなど、コードに直書きしたくない値を1ファイルにまとめておくためのファイル。プロジェクトごとに置いておくのが一般的です。

ちなみに、自分から「.envを全部読んで」と頼んだことは一度もない。ただ「参照していい?」と聞かれて、何をどこまで読まれるのかよくわからないまま「はい」と答えていただけだ。本当は「この1行だけ読んで」と指定できればよかったのだけど、正直、どれが必要なのかが自分で分かっていなかった。ファイルを開いて確認すればわかるだろうけど、ちょっとめんどくさい。だから範囲の絞りようがなくて、まるごと許可する形になっていた。

そして「参照します」が実際には「ファイルを全部読む」ことだとも、その値が後でコマンドや許可リストに残るとも、その時は思ってもみなかった。

振り返ると、ここでの本当のクセは「.envを全文読ませること」じゃない。よくわからないまま、Claudeが「これしていい?」と聞いてくるたびに、ポンポン許可を出していたことだ。なんでもやってくれるから、つい中身を確かめずに「はい」を押してしまう。便利さに甘えていた、というのが正直なところだと思う。

やり直したこと

許可リストに焼き付いていた10件は、その日のうちに消した。結果、465件あった許可リストは426件まで減って、肝心な「生のパスワードが入った行」は全部消えた。

ただ、消すだけだと根本のところは直っていない。同じやり方を続けていたら、また同じところに焼き付くだけだ。なので、自分の中の「お願いの仕方」を変えることにした。

これまで
curl -u “user:abcd 1234 efgh 5678” https://example.com/wp-json/… と、パスワードを直接コマンドに書いて実行させる。.envもまるごと読まれる状態のままだった。
これから
curl -u “$WP_USER:$WP_PASS” https://example.com/wp-json/… のように環境変数で渡す。.envは「この行だけ読んで」と範囲を指定する。

右側のやり方にしておくと、許可リストには変数名しか焼き付かない。値そのものは、その場限りの環境変数として展開されるだけで、設定ファイルには残らない。

※「環境変数」とは、ターミナルの中だけで一時的に覚えておく名札のようなもの。export WP_PASS=xxxx のような形で先にセットしておけば、$WP_PASS と書くだけでその場で値に置き換わります。

もうちょっと早く身につけたかった習慣

振り返ると、これは「設定が肥大化したから気づいた」だけで、もし肥大化していなかったらずっと放置されていた気がする。10件のパスワードが、誰にも気づかれずに、設定ファイルの中で眠り続けていたかもしれない。

AIに何かを頼むとき、便利なのは「全部見せる」「全部任せる」やり方。でもその便利さの裏で、見せた情報がどこかに「焼き付く」ことがある。とくに認証情報のような、後から消したくても消し切れないものは、最初から見せない方が安全だ。

これから①:認証付きのコマンドは、必ず変数($WP_PASS など)で書く
これから②:.envは全文読ませず、必要な1行だけ範囲を指定して読ませる
これから③:許可リストは定期的に棚卸しして、不要な行・敏感な行を消す

これを書いている時点で、自分はこの3つを意識する側に回ったところ。同じ場所で同じように戸惑う人が少しでも減ればうれしいな、と思いつつ、ここに書き残しておくことにした。