所有文章

Claude Code settings.local.json 泄露密钥怎么办:先换密钥,再停止跟踪并加 .gitignore(2026)

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

Claude Code settings.local.json 泄露密钥:黏土文件图标带齿轮,旁边是黏土钥匙和挂锁,柔和自然光

先说结论:如果你的仓库里提交过 .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。

还有别的 Claude Code 报错要查?

看 Claude Code 报错速查。

留下你的想法

你的邮箱不会公开。