Claude Codeのsettings.local.jsonに残る秘密情報の点検と対処
「はい、今後は聞かないでください」を選ぶと、パスワード入りのコマンドが .claude/settings.local.json に残ることがあります。公開リポジトリでは1,122ファイルで実際の秘密情報が見つかりました。git での点検、追跡解除、再発行の手順をまとめます。
「今後は聞かない」で settings.local.json に何が残るか
Claude Code の権限プロンプトで Bash コマンドに「Yes, and don't ask again」(日本語ドキュメントの表記では「はい、今後は聞かないでください」)と答えると、その承認は .claude/settings.local.json に allow ルールとして保存されます。承認したコマンドの中にパスワードやトークンが直接書かれていれば、その文字列もルールと一緒にファイルに入ります。このファイルを git にコミットすると、秘密情報はリポジトリの履歴に残り、公開リポジトリなら誰でも読めます。
以下は、この選択肢をすでに何度か押した開発者のための点検手順です。仕組みを確認し、自分のリポジトリを git コマンドで調べ、見つかった場合の対処と再発防止まで順に進めます。
保存される文字列については、ドキュメントの書き方に注意が必要です。Claude Code のドキュメントは「allow ルールとして保存する」とだけ書いていて、常にコマンド全体がそのまま保存されるとは書いていません。プロンプトが npm test * のようなパターンを提案する場合もあります。一方でセキュリティ企業の Apiiro は、16 種類のコーディングエージェントの承認の保存方法を比べ、承認したコマンド全体を既定でプロジェクト内のファイルに書き込むと確認できたのは Claude Code だけだったと報告しています。自分のファイルに何が入っているかは、後の手順で中身を見て確かめてください。
ドキュメントによると、ファイル変更の承認はファイルに保存されません。永続的な承認として残るのは、Bash コマンド(リポジトリとコマンドごと)と WebFetch のドメインです。CLI(コマンドラインインターフェース)では、Claude Code が書き込むのはこのローカルファイルだけです。VS Code 拡張では承認カードで保存先を選べて、チームで共有するプロジェクト設定ファイルも選べます。そこを選ぶと、ルールはリポジトリを使う全員に適用されます。VS Code 拡張を使っている人は、.claude/settings.json も同じように点検してください。
settings.local.json はどのディレクトリに作られるか
v2.1.211 以降、多くの場合ファイルは git リポジトリのルートに置かれます。その場合、サブディレクトリで Claude Code を起動しても、読み書きするのはルートのファイルで、承認はリポジトリ全体に効きます。worktree の中では、メインのチェックアウトのルートが使われます。ただし Windows などではルートが使われません。例外の条件はこの章の後半にまとめます。
v2.1.211 より前のバージョンは、起動したディレクトリにファイルを作っていました。現在のバージョンは、古いバージョンが残したそのファイルもルートのファイルと合わせて読み込みます。つまり、点検の対象はルートの 1 つだけではありません。サブディレクトリに残った古いファイルも探す必要があります。
次のどれかに当てはまる場合、ファイルはルートに移らず、.claude/settings.json と同じ場所に置かれます。セッションが git リポジトリの外で動いている場合。リポジトリのルートがホームディレクトリの場合。OS が Windows の場合。リポジトリのルート、その .git、その .claude のどれかが自分のユーザーの所有でない場合です。
ここに書いた挙動は、2026年11月9日に読んだ code.claude.com のドキュメントに基づきます。バージョン番号が明記されているのは v2.1.211 のルートへの移動だけです。手元のバージョンは claude --version で確認し、ドキュメントと照らし合わせてください。
Claude Code が自動で追加する除外ルールと、その穴
Claude Code は、まだこのファイルを無視していない git リポジトリで初めてファイルを書き込むときに、**/.claude/settings.local.json というパターンをグローバルな git 除外ファイルに追加します。追加先は次の順で決まります。
- グローバル git 設定の
core.excludesFileが絶対パスか~で始まるパスなら、そのファイル。 - それ以外で
XDG_CONFIG_HOMEが設定されていれば、$XDG_CONFIG_HOME/git/ignore。 XDG_CONFIG_HOMEが設定されていなければ、~/.config/git/ignore。
git 自身の既定値も同じく $XDG_CONFIG_HOME/git/ignore で、未設定か空なら $HOME/.config/git/ignore です。ただし Claude Code は core.excludesFile が相対パスの場合はそれを使いません。この点だけ git の解釈と食い違うことがあります。
Apiiro は「このルールはリポジトリ自身の .gitignore には入らない。だからプロジェクトと一緒に移動する保護は何もない」と指摘しています。Claude Code のドキュメントも、触れているのはグローバル除外ファイルだけです。また、自分の手でファイルを作り、Claude Code がまだ一度も書き込んでいない場合は、自分で .gitignore に追加するようドキュメントは案内しています。
保護がプロジェクトではなく、あなたのホームディレクトリにあることが問題です。ここから次の穴が生まれます。いずれもドキュメントの記述ではなく、グローバル除外ファイルの仕組みから導いた推論です。
- 別の PC や VPS、コンテナでは、そのユーザーの除外ファイルにルールがあるとは限りません。プロジェクトのディレクトリを丸ごとコピーして
git add -Aすると、ファイルがコミットに入ります。 - git リポジトリの外で作業を始めた場合、ドキュメントの説明ではルールは追加されません。後から
git initしてgit add -Aすると、その時点でルールがなければファイルが入ります。 - 手で作ったファイルには、Claude Code が書き込むまでルールが追加されません。
- すでに git が追跡しているファイルには、どの除外ルールも効きません。gitignore のマニュアルにある通り、
.gitignoreは追跡済みのファイルに影響しないからです。
最後の点には続きがあります。ドキュメントによると、ファイルが git で追跡されていると、Claude Code はそれを「リポジトリが提供した設定」として扱い、フォルダを信頼するまでそのルールを保留します。Apiiro は、Claude Code はファイルが追跡されていることに気づくものの、ユーザーには知らされず、次の承認はその追跡中のファイルに追記されると報告しています。これは Apiiro が 2026年11月に観察した挙動で、Anthropic が文書化した仕様ではありません。
公開リポジトリで実際に見つかった秘密情報の数
Apiiro は 2026年11月5日に調査結果を公開し、11月8日に追記しています。2026年11月1日から3日に GitHub のコード検索とコミット検索を読み取り専用で使い、103,617 のリポジトリから公開されている .claude/settings.local.json を 104,185 ファイル集めました。そのうち 1,122 ファイルに実際に使える秘密情報が入っていました。
このグラフのデータ
[
{
"category": "\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30d1\u30b9\u30ef\u30fc\u30c9",
"count": 379
},
{
"category": "Supabase service-role \u30ad\u30fc",
"count": 122
},
{
"category": "Supabase \u30a2\u30ab\u30a6\u30f3\u30c8\u30c8\u30fc\u30af\u30f3",
"count": 103
},
{
"category": "SSH \u30ed\u30b0\u30a4\u30f3",
"count": 43
},
{
"category": "AWS \u30ad\u30fc",
"count": 23
}
]一番多いのはデータベースのパスワードで 5 件でした。Supabase の service-role キーが 122 件、SSH のログイン情報が 43 件です。開発中に psql や ssh をパスワード付きで一度承認すると、その一行がそのまま残る、という使い方の結果だと読めます。
既存のスキャナーでは足りない、という点も重要です。
このグラフのデータ
[
{
"tool": "gitleaks",
"files_flagged": 564
},
{
"tool": "TruffleHog",
"files_flagged": 643
},
{
"tool": "\u3069\u3061\u3089\u3082\u691c\u51fa\u305b\u305a",
"files_flagged": 215
}
]gitleaks が検出したのは 564 ファイル、TruffleHog は 643 ファイルでした。どちらのツールも検出しなかったファイルが 215 あります。見逃しの多くは、PGPASSWORD= や sshpass -p のように、コマンドの中に打ち込まれたパスワードでした。スキャナーはキーの形式で秘密情報を見分けることが多く、ただの文字列としてコマンドに混ざったパスワードには反応しにくいからです。そこで後の点検手順では、こうした書き方そのものを grep で探します。
GitHub 以外では、Apiiro は GitLab.com の公開コピーを 69 件確認し、そのうち 2 件に実際の秘密情報(GitLab のアクセストークンを含む)が入っていたと報告しています。調査は GitHub の検索と、この GitLab.com の 69 件が中心です。自社運用の GitLab や Gitea、Backlog は調査の対象に入っていません。
自分のリポジトリを点検する手順
順番に意味があります。先に「追跡されているか」を確かめ、その後で「無視されているか」を確かめます。git check-ignore は追跡済みのファイルについて何も表示しないので、順番を逆にすると判断を誤るからです。
まずリポジトリのルートに移動し、リモートの最新のブランチを取得します。
cd "$(git rev-parse --show-toplevel)"
git fetch --all手順 1: 追跡されているか確認する。
git ls-files '*settings.local.json'git のパス指定では * がディレクトリ区切りの / も含めてマッチするので、ルートの .claude/settings.local.json も、古いバージョンがサブディレクトリに残したものも一度に出ます。何も表示されなければ、現在のインデックスには入っていません。パスが 1 行でも表示されたら、そのファイルは追跡中で、どの除外ルールも効いていません。
手順 2: 無視されているか確認する。
git check-ignore -v .claude/settings.local.json無視されていれば、どのファイルの何行目のどのパターンでマッチしたかが表示されます。表示された元のファイルがグローバル除外ファイルなら、守られているのはこのマシンのこのユーザーだけです。何も表示されない場合は、無視されていないか、手順 1 で見た通り追跡中かのどちらかです。追跡中のパスについてもルールを調べたいときは --no-index を付けます。
グローバル除外ファイルの中身も見ておきます。
git config --global --get core.excludesFile
cat "${XDG_CONFIG_HOME:-$HOME/.config}/git/ignore"1 行目が何も表示しなければ、core.excludesFile は設定されていません。2 行目で No such file or directory が出たら、そのマシンにはグローバル除外ファイルがありません。
手順 3: 過去のコミットに入ったことがないか確認する。
git log --all --oneline -- .claude/settings.local.json
git log --all --oneline -- '*settings.local.json'--all は取得済みのすべてのブランチとタグを対象にします。コミットが 1 つでも表示されたら、今は追跡されていなくても、ファイルは履歴に残っています。公開リポジトリなら、その時点で中身は公開されたものと考えてください。
手順 4: 中身に秘密情報がないか確認する。
まず作業ツリーにあるファイルを全部探します。
find . -path '*/.claude/settings.local.json' -not -path '*/node_modules/*'次に allow ルールを一覧にして、目で読みます。jq がなければ sudo apt install -y jq で入ります。
jq -r '.permissions.allow[]?' .claude/settings.local.jsonよくある書き方を grep でも探します。対象は、PGPASSWORD=、MYSQL_PWD=、mysql -pパスワード の形、sshpass -p、Bearer を含む認証ヘッダー、ユーザー:パスワード@ を含む接続文字列です。
grep -nE 'PGPASSWORD=|MYSQL_PWD=|mysql[^"]* -p[^ "]|sshpass -p|Bearer |://[^/:@ ]+:[^/@ ]+@' .claude/settings.local.json履歴に入ったことがある場合は、過去の全バージョンの差分にも同じパターンを当てます。
git log --all -p -- '*settings.local.json' | grep -nE 'PGPASSWORD=|MYSQL_PWD=|mysql[^"]* -p[^ "]|sshpass -p|Bearer |://[^/:@ ]+:[^/@ ]+@'grep が何も返さなくても、安全とは言い切れません。パターンは出発点にすぎないので、API キーをヘッダー以外で渡すコマンドや、独自のツールのオプションは拾えないからです。jq の一覧を最後まで読むのが確実です。
見つかったときの対処: 追跡をやめ、ルールを消し、認証情報を再発行する
追跡中だった場合は、インデックスから外して、リポジトリ自身の .gitignore に除外ルールを書きます。グローバル除外ファイルではなくリポジトリに書くのは、ルールをプロジェクトと一緒に運ぶためです。
git ls-files -z '*settings.local.json' | xargs -0 -r git rm --cached --
echo '**/.claude/settings.local.json' >> .gitignore
git add .gitignore
git commit -m 'Stop tracking Claude Code settings.local.json'
git pushgit ls-files '*settings.local.json' をもう一度実行し、何も表示されなければ追跡は止まっています。git check-ignore -v .claude/settings.local.json は、今度はリポジトリの .gitignore の行を示すはずです。
git rm --cached が変えるのはインデックスだけです。作業ツリーのファイルは残り、秘密情報もディスク上に残ります。過去のコミットからも消えません。次に、エディターでファイルを開き、秘密情報を含む allow ルールを削除します。Apiiro は、一度もコミットしていないファイルでも秘密情報を含むルールは削除するよう勧めています。ディスク上のファイルは、バックアップや別のツールからも読まれるからです。編集後は jq . .claude/settings.local.json で JSON が壊れていないか確認します。エラーが出なければ形式は正しいです。
そして、ファイルに一度でも入った認証情報は、すべて再発行(ローテーション)します。Apiiro の助言の中心はここです。追跡をやめても、履歴、フォーク、他人のクローンには元のファイルが残ります。履歴を書き換えても、すでに作られたフォークやクローンは書き換わりません。データベースのパスワードを変え、API キーやトークンを失効させてから新しいものを発行します。手順は各サービスの管理画面やドキュメントに従ってください。再発行が終わるまで、漏れた値は有効なままです。
npm パッケージに入っていないか確認する
@IT(ITmedia)は 2026年4月28日、Lakera の調査を報じました。Lakera が監視していた約 46,500 の npm パッケージのうち、428 パッケージが .claude/settings.local.json を含んでいました。そのうち約 30 パッケージ、33 ファイルに実際の認証情報が入っていて、記事はこれを「13件に1件」の割合と表現しています。
記事によると、Lakera は npm が既定では .claude/ を除外しないと指摘し、.claude/ を .npmignore と .gitignore の両方に入れ、公開前に npm pack --dry-run で中身を確認するよう勧めています。公開済みの認証情報は取り消せないので、再発行が必要です。
npm pack --dry-runnpm のドキュメントによると、--dry-run は何も変更せず、実行した場合に何をするかを報告するだけです。報告の中に .claude/ のパスがないか確認します。
除外の仕組みには細かい点があります。npm は .npmignore がなければ .gitignore の内容を使います。逆に言えば、.npmignore を作った時点で .gitignore は npm に使われなくなります。リポジトリの .gitignore に除外ルールを書いただけで安心せず、.npmignore があるなら、そこにも .claude/ を書いてください。また、ルートの .npmignore は package.json の files フィールドを上書きしません。files を使っているパッケージでは、そこに .claude が含まれないようにします。
GitHub 以外でホストしている場合(GitLab、Gitea、Backlog)
GitHub のシークレットスキャンは、リポジトリの全履歴とすべてのブランチを対象にし、公開リポジトリでは無料で自動的に動きます。プライベートや内部のリポジトリでは、Team または Enterprise Cloud の GitHub Secret Protection が必要です。ユーザー向けのプッシュ保護は既定で有効で、公開リポジトリへの秘密情報のプッシュを止めます。ただしこれらは GitHub の機能なので、自社運用の GitLab や Gitea、Backlog のリポジトリには届きません。
GitLab には独自のシークレット検出があります。ドキュメントによると Free、Premium、Ultimate のすべてで使え、GitLab.com、GitLab Self-Managed、GitLab Dedicated に対応しています。CI/CD(継続的インテグレーションと継続的デリバリー)のパイプラインの中で動き、既定のブランチへのコミットを調べます。設定すれば、マージリクエストのパイプラインでより早く調べることもできます。自社運用の GitLab なら、まずこれが有効か確認してください。
Gitea と Backlog については、組み込みのシークレットスキャンの有無を確認できていません。利用しているホストのドキュメントを確認し、なければ CI に gitleaks や TruffleHog のようなスキャナーを入れます。ただし Apiiro の数字の通り、どちらも検出しなかったファイルが 215 ありました。前の章の grep を CI の手順にも加えておくと、コマンドに埋め込まれたパスワードを拾える可能性が上がります。
再発を防ぐには、どう承認すればよいか
パスワードをコマンドに書かない。 Apiiro は、秘密情報を環境変数で参照するよう勧めています。たとえば psql "$DATABASE_URL" のように書けば、承認ルールに残る文字列は変数名だけで、値は残りません。値そのものは セルフホストのシークレットマネージャーなどで管理し、シェルを起動するときに読み込みます。エージェントの手の届く場所にそもそも秘密情報を置かない設計は、AI エージェントから秘密情報を遠ざける方法で詳しく扱っています。
具体的なコマンドではなく、プレフィックス(先頭部分)のルールを承認する。 ドキュメントによると、* のない Bash ルールは 1 つの正確なコマンドにだけマッチし、* はスペースを含む任意の文字列にマッチします。ドキュメントの設定例は次の形です。
{
"permissions": {
"allow": [
"Bash(npm run lint)",
"Bash(npm run test *)"
],
"deny": [
"Read(./.env)",
"Read(./.env.*)"
]
}
}このようにルールを自分で書いておけば、プロンプトで「今後は聞かない」を押す回数が減り、ファイルに残る文字列も自分で決められます。プロンプトが npm test * のようなパターンを提案した場合は、具体的なコマンドよりそちらを選ぶ方が安全です。注意点は 2 つあります。プレフィックスには絶対にパスワードを含めないこと。そして * の後ろには何でも入るので、Bash(psql *) のような広すぎるルールは避けることです。承認の範囲と auto モードの考え方は、Claude Code の auto モードと権限ルールを参照してください。
全リポジトリの .gitignore に除外ルールを書く。 グローバル除外ファイルは自分のマシンしか守りません。**/.claude/settings.local.json をリポジトリの .gitignore と、新しいリポジトリのテンプレートに入れておけば、別のマシンでもチームの誰がクローンしても同じルールが効きます。Claude Code を VPS やコンテナで動かす人は、そのマシンごとにグローバル除外ファイルの状態が違います。VPS で Claude Code を安全に動かす方法の手順と合わせて、マシンを作るたびに確認してください。
定期的に中身を読む。 jq -r '.permissions.allow[]?' .claude/settings.local.json は数秒で終わります。リリースの前や、リポジトリを公開に切り替える前に一度読む習慣をつければ、残った一行に気づけます。
Anthropic の見解と、修正の予定
Claude Code チームの Boris Cherny 氏は、2026年11月7日(UTC、日本時間では11月8日)に Hacker News のコメントで「Historically Claude Code has not done secret scrubbing (there are many good tools for that)」と書きました。これまで Claude Code は秘密情報の除去をしてこなかった、という意味です。Apiiro も 11月8日の追記でこの一文を引用しています。
同じコメントの続きで Cherny 氏は、防止のためにできることを検討していると述べています。その約 8 分後に投稿した別のコメントでは、案として、auto モードがこのケースを捕まえるようにすること、基本的なシークレットスキャンを組み込むこと、その他のアイデアを挙げました。そのコメントには、出荷の前にいくつか試作してトレードオフを理解する、とも書いていて、修正の時期は示していません。2026年11月9日時点で、修正は発表されていません。
Cherny 氏はまた、Claude Code はファイルを作るときに git の除外ルールを追加するので、公開されたコピーは手で作ってコミットされたものだろう、という趣旨の見方を示しました。Apiiro はこれに反論し、Claude Code 自身がファイルを追加したコミットを数えています。どちらの見方を取るにしても、点検と再発行の手順は変わりません。Cherny 氏自身も、どのエージェントを使う場合でも、ソースコードのホストでシークレットスキャンを有効にするよう勧めています。
FAQ
.gitignore に書いてあれば settings.local.json は安全ですか?
追跡されていなければ、これからのコミットには入りません。ただし、すでに git が追跡しているファイルには .gitignore が効きません。先に git ls-files '*settings.local.json' で追跡の有無を確かめ、パスが表示されたら git rm --cached で外してください。過去に一度でもコミットされていれば、git log --all -- .claude/settings.local.json にコミットが表示され、中身は履歴に残っています。
ファイルを消して履歴を書き換えれば、パスワードの変更は不要ですか?
不要にはなりません。フォーク、他人のクローン、公開中にコピーされたものは、あなたの履歴を書き換えても変わらないからです。Apiiro は、ファイルに一度でも入った認証情報はすべて再発行するよう勧めています。データベースのパスワードを変え、トークンやキーを失効させてから、新しい値を発行してください。
自社運用の GitLab や Gitea、Backlog でも点検は必要ですか?
必要です。GitHub のシークレットスキャンは GitHub の機能なので、自社運用のホストには届きません。GitLab には Free を含むすべてのプランで CI パイプラインのシークレット検出があります。Gitea と Backlog は各ドキュメントで組み込みのスキャンの有無を確認してください。スキャナーを入れる場合も、Apiiro の調査では gitleaks と TruffleHog のどちらも検出しなかったファイルが 215 あったので、PGPASSWORD= や sshpass -p を探す grep を併用してください。
Claude Code 側でこの問題は修正される予定ですか?
2026年11月9日時点で、修正は発表されていません。Claude Code チームの Boris Cherny 氏は 2026年11月7日(UTC)に Hacker News で「Historically Claude Code has not done secret scrubbing」と書き、続く別のコメントで auto モードでの検出や基本的なシークレットスキャンの組み込みを案として挙げて、いくつか試作すると述べましたが、時期は示していません。修正を待たずに、自分のリポジトリを点検してください。
どの承認が settings.local.json に保存されますか?
Claude Code のドキュメントによると、永続的に保存されるのは Bash コマンド(リポジトリとコマンドごと)と WebFetch のドメインの承認です。ファイル変更の承認は保存されません。CLI では書き込み先はローカルファイルだけですが、VS Code 拡張では承認カードで共有のプロジェクト設定ファイルを選べるので、その場合は .claude/settings.json に入り、チーム全員に適用されます。