Claude Code settings.local.json 泄露密钥怎么办:先换密钥,再停止跟踪并加 .gitignore(2026)
选「Yes, and don't ask again」时,带密码的命令会被原样存进 .claude/settings.local.json。Apiiro 在公开 GitHub 找到 1,122 份含密钥的副本。修法:先换密钥,再停止跟踪、加 .gitignore;改写历史是单独的高风险步骤。

先说结论:如果你的仓库里提交过 .claude/settings.local.json,先别急着删文件,第一步是把里面出现过的密钥全部换掉,第二步才是停止跟踪并把它写进仓库自己的 .gitignore。原因是:Claude Code 在你选「Yes, and don’t ask again」时,会把批准的命令原样存成一条 allow 规则,命令里带的密码或 token 也一起存进去了。安全公司 Apiiro 在 2026 年 11 月初披露,在公开 GitHub 上找到 104,185 份这个文件,其中 1,122 份至少含一个密钥。本文的依据只有 Apiiro 的研究、Anthropic 和 GitHub 的官方文档;示例里的密钥全是虚构的,扫描输出只给文件路径和命中类型。
这个文件是什么,密钥怎么进去的
.claude/settings.local.json 是 Claude Code 的「项目本地」设置文件,只属于你自己、只对这一个项目生效。官方设置文档写明:你在权限提示里选「Yes, and don’t ask again」批准一条 Bash 命令时,Claude Code 会把这次批准存成一条 allow 规则,写进 git 仓库根目录的这个文件。
规则有两种形态:模式(例如 npm test *)和一条完整的命令。官方权限文档说明,没有 * 的规则只匹配这一条完整命令。当你批准的是一条带密码的完整命令,密码就以明文留在文件里了。 结构大致是这样的(占位符是虚构的):
{"permissions":{"allow":["Bash(PGPASSWORD=<明文密码> psql -h <主机> -U <用户> -c '...')"]}}
为什么会传到 GitHub
官方文档说,Claude Code 第一次在 git 仓库里写这个文件时,会把 **/.claude/settings.local.json 加进你全局的 git 排除文件,所以这台电脑上的所有仓库都不会提交它。文档同时写明:如果文件是你手工创建的,要自己把它加进 .gitignore。
问题在于这个保护只存在于「这一台电脑的这一份 git 配置」里。按 Apiiro 的说法,Claude Code 不会把它写进项目自己的 .gitignore,所以保护不会随项目走:换一台电脑克隆、放进容器、把一个文件夹后来才变成仓库、或者文件已经被跟踪过,保护都不起作用。Apiiro 追踪了 1,105 个仓库,其中 539 个有带 Claude 共同作者署名的提交改动过这个文件,他们据此推测 Claude 经常自己提交了它。这是他们的推断,不是 Anthropic 的说法。
研究发现了什么
数字来自 Apiiro 的研究,由 The Hacker News 报道。我们核对时,Apiiro 自己的文章被网站的验证页拦住,打不开。下面列出的数字,包括 63 个组织和共享 settings.json 的 298 份,都出现在这篇 Hacker News 报道里。Ars Technica 也报道了这项研究(部分总数取了整数)。
- 公开 GitHub 上有 104,185 份
.claude/settings.local.json(分布在 103,617 个仓库)。 - 其中 1,122 份(约 1.1%)至少含一个密钥,合计 1,379 个不同的密钥,来自 63 个组织。
- 另有 734 个密钥只存在于这个文件的旧版本里(通常是文件后来被删了),分布在 509 个仓库;211 个 fork 带着和原仓库一样的密钥。
- Apiiro 没有测试这些密钥现在还能不能用,所以这是「暴露」,不是「已被入侵」。研究者通知的一家公司确认过它的密钥当时有效。
- 两款常见的密钥扫描器 gitleaks 和 TruffleHog 都没标出其中 215 份文件,多数是命令里直接写的密码。
- 报道里还有「2,539 个密钥」这个数,它把历史记录、共享的
settings.json和聊天记录也算进去了,和上面的 1,379 口径不同。
怎么修,按这个顺序做
1. 先换密钥,再做别的
GitHub 官方文档的第一条就是:敏感数据如果是密钥,第一步是吊销或轮换,轮换之后它就不能再用于访问,有时这一步就够了。把这个文件里出现过的密码、token 和 key 全部换掉,包括只存在于旧提交里的。优先级:能直接开数据库的密码、云厂商的 key、SSH 登录、GitHub / GitLab / npm 的 token。Anthropic、OpenAI、DeepSeek 的 key 怎么删怎么换,见 API key 泄露怎么办。
2. 查一下哪些仓库、哪些提交里有它
在每个仓库里列出被跟踪的文件,和历史里出现过的路径(这两条只打印路径和提交摘要,不会打印文件内容):
git ls-files '*settings.local.json'
git log --all --name-only --pretty=format: -- '*settings.local.json' | sort -u
再用下面这段只打印「路径 + 命中类型」的小循环粗扫当前被跟踪的文件。它只是示例,规则很简单,不能代替正规的密钥扫描工具:
for f in $(git ls-files '*settings.local.json'); do
grep -qE 'PGPASSWORD=|sshpass -p|mysql .* -p' "$f" && echo "$f hit: password-in-command"
grep -qiE '(token|secret|api[_-]?key|password)=' "$f" && echo "$f hit: key-or-token-assignment"
done
输出长这样(路径是虚构的):
.claude/settings.local.json hit: password-in-command
apps/api/.claude/settings.local.json hit: key-or-token-assignment
这几条命令我们在一个临时仓库里用假密码跑过(git 2.47.3),输出只有路径、命中类型和提交摘要。如果你是团队,也可以在 GitHub 组织里搜索 .claude/settings.local.json 和 .claude/settings.json,研究者建议两个都查,因为共享的 settings.json 里也出现过密钥(298 份,Apiiro 的研究,由 The Hacker News 报道)。
3. 停止跟踪,并写进仓库自己的 .gitignore
只加 .gitignore 不够:已经被跟踪的文件不会因此被忽略,要先让 git 停止跟踪它(--cached 只从 git 里移除,不删你本地的文件):
git rm --cached .claude/settings.local.json
echo ".claude/settings.local.json" >> .gitignore
git add .gitignore
git commit -m "Stop tracking Claude Code local settings"
这几步我们在临时仓库里验证过:执行后 git ls-files 不再列出该文件,git check-ignore -v 显示 .gitignore 生效。注意它不会清除历史里的旧版本。
4. 清掉本机文件里带密钥的规则
打开你自己电脑上的这个文件(哪怕从没提交过),删掉所有含密码、token 的规则。以后批准时选模式,别批准带密码的完整命令;密码用环境变量或密钥管理工具,让命令里只出现变量名,这样存下来的规则里没有密码本身。官方权限文档里,Bash(npm run build) 只匹配这一条命令,带 * 的规则匹配一类命令,批准时选后者更稳。
单独一步(高风险):要不要改写 Git 历史
这一步不是必须的,而且风险高,和上面几步分开考虑。 GitHub 官方文档说得很直白:密钥已经轮换之后,它不能再被用来访问,额外去改写历史「可能没有必要」。改写历史的副作用包括:
- 很容易再次污染:同事如果拿着改写之前的克隆直接拉取再推送,旧数据会被推回来,他们必须重新克隆。
- 可能丢掉别人的工作:别人继续在旧分支上提交的内容会和改写后的历史冲突。
- 改写不会清掉 fork、本地克隆和 GitHub 上缓存的视图,已经被别人拿走的副本也收不回来。
所以顺序是:先轮换密钥,确认旧密钥在服务商后台已失效;只有当你有明确理由(比如文件里还有无法更换的数据)才考虑改写历史,并且要先通知所有协作者、先在仓库的备份镜像上演练。本文不提供可复制的改写和强制推送命令,具体做法请只看 GitHub 官方的 Removing sensitive data from a repository(它推荐的工具是 git-filter-repo)。
以后怎么防
- 团队的
.gitignore模板里加上.claude/settings.local.json;研究者还建议把.claude/、.cursor/、.gemini/这类 agent 目录当成和.env一样会含密钥的地方。 - 在 pre-commit 和 CI 里加密钥扫描,并且要能扫出「命令里的明文密码」,不只是已知格式的 key,因为 gitleaks 和 TruffleHog 漏掉了那 215 份。
- 命令里不要出现密码,用环境变量;批准权限时选模式。
- Anthropic 方面:Claude Code 的 Boris Cherny 在 Hacker News 上说,团队在研究怎么防止这种情况,建议用自动模式和密钥扫描;但有用户指出自动模式下敏感命令仍可能被存进设置文件,他回应说是个好发现,团队还在想办法改进。官方是否会改动,我们没有看到公告,以后以官方文档为准。
常见问题
把文件删掉就行了吗?
不行。旧版本还在 git 历史里,fork 里也可能有。先轮换密钥。
我的仓库是私有的,要紧吗?
研究只统计了公开仓库,私有仓库没有数据。但密钥以明文写在文件里,能读仓库的人都能读到,所以只要文件里出现过密钥,就按同样的顺序处理。
它和 settings.json 是一回事吗?
不是。settings.json 是共享或个人的设置,settings.local.json 是项目里只属于你的那份。路径和优先级见 settings.json 位置在哪;/permissions 怎么用见 Claude Code /permissions。