平时用 Claude Code
进行连接数据库、登录服务器或者调用外部接口等操作,我们经常在终端中看到一个确认对话框。为了避免每次都要按回车键,很多人会默认选择第
2 个选项,即允许并以后不再询问。项目文件夹里面有一个
.claude/settings.local.json
配置文件,专门用来记录本机放行的规则。点击这个按钮之后,工具一方面会记住你允许使用这个数据库连接工具,另一方面也会把你输入的整行带明文密码和公网
IP 的命令原封不动拷贝到这个文件里。
安全组织 Apiiro 最近发布了一份扫描报告,在 GitHub 上的 1,994 个公开代码仓库里,发现了 2,539 个由这种配置暴露出来的有效密钥。很多程序员以为他们从来没手动把配置文件夹传到代码库中过。但 Apiiro 在追查提交历史之后发现,近一半的泄露文件是主人叫 Claude 帮忙提交代码,Claude 亲手打包传上 GitHub 的。
这一切都源于一次次的图省事顺手放行。你让 AI
帮忙查一下线上测试库的数据,或者登录远端机器看一眼日志,AI
经常会拼出一行单次运行的完整终端命令。为了省掉交互弹窗,它会把密码直接塞进命令行里,拼成
PGPASSWORD=明文密码 psql -h 公网地址 或者
sshpass -p 明文密码 ssh root@公网地址
这样的格式。你一旦点下允许且不再询问,这整句话就会原样写进
.claude/settings.local.json
的白名单数组里。一个原本用来记权限开关的文件,就这样变成了同时存着大门钥匙和门牌号的明文密码本。
这本密码本已经在公开代码库里铺开了。前面提到的 1,994 个仓库、2,539
个密钥,覆盖了历史提交记录和共享配置等多个地方;即便只看现在还挂在
GitHub 默认分支上的 104,185 个 .claude/settings.local.json
文件,其中也有 1,122 个文件直接存着明文凭证。
这批现存文件里一共直接存着 1,379 个有效凭证。它们在默认分支上躺了中位数 217 天,一直处于公开可查的状态。
其中光是有公网地址的数据库密码就有 379 个,公网服务器的登录口令有 43 个。此外还有 122 个可绕过所有数据行安全策略的 Supabase 服务端高权限密钥,以及 103 个能控制账户下所有项目的 Supabase 账户令牌,其余则是各类云平台与第三方接口钥匙。
为什么这么多团队都装了防泄密扫描器,却仍然无法阻止这些文件的泄露呢?研究人员使用开源社区最常用的两种检测工具
gitleaks 和
TruffleHog,对这批已知的含有敏感信息的文件进行了扫描。令人惊讶的是,这两款工具竟然同时遗漏了
215 个文件,漏检率达到了
19.2%。究其原因,传统的扫描工具通常依赖于识别带有 sk- 或
ghp_
等前缀的乱码密钥。然而,一旦这些数据库明文密码隐藏在普通的命令行参数中,它们对扫描工具来说并不比普通的英文单词更为显眼。
这份报告在 11 月 7 日发上 Hacker News 以后,引发了大量开发者的追问。Claude Code 的团队负责人 Boris Cherny 当天就出来解释,这个本地配置文件本意就是为了留在单机上才设计的。他声称 Claude Code 创建这个文件时会自动把文件加到 gitignore 里,所以泄露的文件都是用户手动创建并且签入仓库的。
但翻开 Claude Code v2.1.299
客户端的安装包代码,就会发现真实逻辑跟他的说法对不上。早期版本的确会将忽略规则写入随代码库移动的
.gitignore 文件中。但有用户抱怨工具修改了项目文件后,官方在
2025 年底改变了这一策略,多张社区报错工单都提及了这一更改导致的泄密。目前,客户端在创建
.claude/settings.local.json 时不会修改项目自身的
.gitignore,而是在只存在于当前这台电脑上的全局 Git 忽略清单
~/.config/git/ignore 中写入一个条目。
这种只针对当前电脑的机制,在两个常见场景下会直接失效。第一种情况,如果你在一个新建的空文件夹里先用
Claude 并点了不再询问,之后才运行 git init
初始化代码库,客户端当时没检测到代码库,就会直接跳过不写忽略规则。第二种情况,就算客户端往当前电脑写上了全局忽略规则,那条规则也只留在这台电脑上;一旦你把项目拷到另一台电脑或放进容器里,保护就自动消失了。
类似地,遇到打包发布软件包的场景,打包的工具也不会去查看 Git 的全局忽略清单。Lakera 安全公司在今年 4 月发布的软件包扫描报告也发现,在公开发布的 428 个 npm 安装包中,它们直接把本地的这个配置文件放了进去,其中有 30 个包放了有效的密钥。
而更致命的是 Claude Code 的提交行为。安装包的代码显示,即使
.claude/settings.local.json 进入了 Git
的追踪列表,客户端在检测后会默默地记录一个内部统计日志,而不会向用户给出任何警告,并且会继续往里面追加新的密码。
到了用户真正让 Claude 帮忙提交代码这一步,防线彻底失守。在官方给
Claude 自己的 Git 提交系统提示词中,特别提醒模型不要提交
.env 或 credentials.json
等机密文件,却偏偏漏掉了自家的
.claude/settings.local.json。因此在 1,105
个可查清历史记录的泄密仓库中,有 539 个是用户让 Claude
帮忙提交代码时,由带着 Co-Authored-By: Claude
署名的提交亲手传上 GitHub 的,占比达 48.8%。
看到这里你可能会想,把命令放到文件之前检查有没有密码,难道是一件很难的事吗?在这次 Hacker News 的讨论里,Boris Cherny 给出的解释是,Claude Code 历史上从来没有做过这个机密清理,因为市场上已经有不少现成的工具,他们正在探索防止泄密的原型方案。
但事实上,社区早在一年多前就已经发现了这个坑。2025 年 8 月 11
日,一位开发者向 Claude Code 的官方仓库提交了一份附带复现步骤的安全漏洞报告,指出获批的命令会原样把明文密码保存在
settings.local.json 里。官方的工程师没有任何回复,搁置近 5
个月后,官方机器人在次年年初直接给这张工单标上不计划修复并自动关掉。
更令人惊讶的是,翻开客户端安装包的云端同步模块,里面明明躺着一段现成的密码过滤代码。这段代码会逐条扫描用户的
permissions.allow
放行规则,一旦发现某条规则看起来包含凭证,就会当场把它剔除,连给用户的提示语都已经写好了。
既然这个现成的过滤代码已经在安装包里了,为什么我们还是可以在本地配置文件里看到明文密码呢?原因在于这段官方提供的过滤代码,只在用户开启官方云端远程会话功能、把本地配置传到 Anthropic 的云服务器上时才启用。但用户点击不再询问并把命令写到本地项目文件夹里,程序就不会调用这个现成的过滤器。只保官方云服务器,不保用户本地代码库,这种双重标准就藏在同一个安装包里。
对此,Boris 在回应中还建议社区成员不要再用放行规则,而改用让后台 AI 分类器来判断命令是否危险的自动模式。但评论区有读者当场指出,自动模式的后台分类器一旦遇到带密码、连外部服务器的敏感命令,按设计就会不敢作主,退回人工弹窗让你点确认。你一点永久允许,密码照样写进同一个文件里。面对这个死循环,Boris 当场只能承认这位读者抓得准,说团队还得再想办法。况且自动模式本身的拦截能力也远没有宣传的那么可靠,香港科技大学在 10 月底刚更新的独立评测测试了 128 个日常开发任务,发现遇到操作范围交代不清的指令,自动模式有 81.0% 的危险动作根本没拦住。
既然我们既不能指望工具自带的单机隐藏功能,也不能指望自动模式,那我们就自己动手把漏洞堵上。现在只需花 30 秒做两件事,就能让你的代码库彻底免疫。
第一步,不信单机全局隐藏,把 .claude/ 写到每个项目自己的
.gitignore 文件里;如果项目要发布软件包,还要写到
.npmignore。你可以在电脑上搜一下现有的
.claude/settings.local.json,看看里面有没有以前顺手放行的明文密码。
第二步是把批准运行什么命令和密码具体是什么彻底分开。平时让 Claude
Code
连数据库或登服务器,不要用明文密码直接写在命令的字面量里,而是用环境变量名,或者用
1Password 的命令行工具 op run --env-file .env -- claude
在启动时把密码注入内存。
这样即使你偷懒点了 100 次允许且不再询问,Claude Code 只会把
PGPASSWORD=$DB_PASSWORD psql -h 主机地址 这样的变量名写到
.claude/settings.local.json。就算这个文件真的传到 GitHub
上,别人拿到的也只是个空壳。