安全公司 Apiiro 在 11 月 5 日公布的一项研究里,揭开了一个让很多开发者后背发凉的事实:Anthropic 的 AI 编程助手 Claude Code 有一个“一键泄露”的设计缺陷。只要开发者在确认弹窗里点过一次“是的,以后不再询问”,他当时批准的那条命令就会被原样写进项目里的一个本地设置文件,连同命令里夹带的真实密码和 API 密钥一起。而这个文件,如今正躺在 1100 多个公开的 GitHub 仓库里,任何人都能下载查看。
先把两个最容易混淆的数字分清楚,因为它们口径不同。Apiiro 在 11 月 1 日至 3 日扫描了 GitHub 上的公开仓库,共找到 104,185 份公开的 .claude/settings.local.json 文件副本,分布在 103,617 个仓库里。其中 1,122 份文件(约 1.1%)含有至少一个真实密钥,合计 1,379 个不同的密钥。这是核心数字,指的是当前版本的本地设置文件本身。
而另一个更大的数字——2,539 个密钥、1,994 个仓库——是 Apiiro 把口径放宽之后得到的总数:除了当前版本的本地设置文件,还包括文件的历史版本、团队有意提交的共享设置文件 .claude/settings.json,以及保存下来的 AI 助手聊天记录。两个数字都来自同一项研究,但统计范围不同,绝不能混为一谈。本文以下提到的 1,122 份文件、1,379 个密钥,均指核心口径。
一次点击,怎么把密码写进仓库
Claude Code 是 Anthropic 推出的终端 AI 编程助手:它读你的代码,提议在你电脑上运行命令,每次执行前都要先征求你的同意。弹窗里有几个选项,其中一个是“是的,以后不再询问”(Yes, and don’t ask again)。点这个选项本意是图省事:同一条命令以后不用再反复确认。
问题就出在这里。Claude Code 会把这条被批准的命令逐字写进项目文件夹里的 .claude/settings.local.json,作为一条永久放行规则。如果这条命令里恰好带有密码或密钥——比如连接数据库的命令里写了明文密码,或者调用某个服务时贴了 API 密钥——密钥就跟着命令一起被写进了文件。
这个文件按设计应该只留在开发者自己的电脑上。Claude Code 也确实做了防护:第一次在某个 Git 仓库里写入这个文件时,它会把路径加进用户个人的全局 git 忽略列表。但关键的漏洞也在这里:全局忽略列表只对本机、本用户有效,不会跟着仓库走。换一台电脑克隆同一个仓库,或者团队里其他成员拉取代码,这层保护就不存在了。正确的做法应该是把文件写进项目自己的 .gitignore,但 Claude Code 没有这么做。
更糟的是,很多时候是 AI 助手自己把文件提交上去的。Apiiro 追踪了 1,105 个含有真实密钥的仓库,发现其中 539 个仓库里,有一笔由 Claude 联合署名的提交修改过这个文件。也就是说,开发者让 Claude Code“把改动提交一下”,它就顺手把装着密码的设置文件也推上去了。Apiiro 还确认,这不是某个模型的问题:用最新的 Opus 5.5 和 Fable 5.1 都能复现同样的行为,这是 Claude Code 产品本身的设计问题。
泄露了什么:从数据库密码到医疗系统管理员口令
这 1,379 个密钥不是什么无害的测试数据。按 Apiiro 的分类,其中 636 个是格式可识别的服务商密钥,包括 AWS、GitHub、npm、Supabase、Stripe、Slack、OpenAI 等平台的密钥;另外 743 个是与公开可达主机配套的密码或令牌。具体到类型:379 个数据库密码、43 个可公开访问服务器的 SSH 登录凭证、42 个 GitHub、GitLab 和 npm 令牌、23 个 AWS 密钥。
研究点名的几个例子足以说明严重性:某数据库厂商自己云服务的管理员级 API 密钥;一个生产环境 Azure Postgres 实例的密码;Square 的一个生产环境令牌;某电子病历系统数据库的管理员密码。Apiiro 统计,63 家机构受到影响,大多数是各规模的软件公司。文件越大,风险越高:超过 8KB 的文件里,每十份就有一份含有真实密钥;而小于 500 字节的文件,这个比例不到五百分之一。
泄露还不是最近才发生的事。在受影响的仓库里,这个文件首次被提交的中位时间是扫描前 217 天,118 个仓库里超过一年。也就是说,很多密钥已经在公开网络上挂了几个月甚至一年以上,任何爬虫、任何别有用心的人都可能已经下载过。
这里必须加一个重要的限定:Apiiro 并没有实际测试这些凭证是否仍然有效。研究方把“真实密钥”定义为“符合已知服务商密钥格式,或者指向公开主机的密码和令牌”,而不是“确认能登录”。唯一得到确认的是一家公司向 Apiiro 证实,其泄露的密钥在被发现时仍然有效。其余密钥是否过期、是否已被轮换,研究没有验证,也无法验证。所以准确的表述是:1100 多个公开文件含有“按格式判断为真实”的密码和密钥,而不是“1100 多个确定可用的有效凭证”。
连扫描器都漏网:五分之一的泄露无人察觉
这件事还有一层更让人不安的含义:常规的安全扫描工具对这类泄露并不灵敏。Apiiro 用两款主流密钥扫描工具做了对照:gitleaks 只标记了 1,122 份含密钥文件中的 564 份,TruffleHog 标记了 643 份,两款工具都没发现的有 215 份,约占五分之一。
原因在于这些密钥的藏身方式。它们不是整齐地躺在 .env 文件里等着被扫描,而是嵌在一条条 shell 命令的参数里,混在 JSON 格式的放行规则中。很多密码没有可识别的服务商前缀,就是一串随机字符加一个主机地址,扫描器的规则库很难覆盖。GitHub 自带的密钥扫描同样依赖已知的密钥格式,对这种形态的泄露基本无能为力。
这意味着“仓库开了 secret scanning 就安全了”是一种错觉。Apiiro 的研究结论很直白:对于这类新型泄露,依赖事后扫描是靠不住的,防线必须前移到密钥不进仓库这一步。
为什么偏偏是 Claude Code:16 个工具里只有它这么干
Apiiro 在研究里做了一个横向对比:它查阅了 16 款 AI 编程助手产品的文档,确认只有 Claude Code 会在默认设置下把完整批准命令写进项目文件。其他工具要么把放行规则存在用户主目录,要么只存命令的模式而不存具体参数,要么根本不设永久放行。换句话说,这不是行业通病,而是 Claude Code 一个产品的设计选择。
这个选择背后的权衡并不难理解。把放行规则存在项目文件夹里,好处是换电脑、换项目时配置跟着走,团队协作也更方便;代价就是配置和代码混在同一个目录里,一旦提交就一起上云。Claude Code 的文档其实写明了这份文件“应该只留在本地”,但它选择的防护手段——写进用户全局忽略列表——恰恰是最容易失效的一种:全局忽略列表保存在用户主目录的 .gitconfig 体系里,重装系统、换电脑、新人入职,都会让这层保护消失,而文件本身还老老实实躺在项目目录里等着被提交。
还有一个细节值得注意。Apiiro 提到,公开的 GitHub 议题记录显示,早在 2025 年 8 月就有人报告过这个问题。研究方引用的四份相关报告都没有得到 Anthropic 的公开回复,其中三份还被机器人以“长期无活动”或“重复”为由自动关闭。截至 11 月 8 日,Anthropic 既没有就这项研究发表声明,也没有修改相关文档。一个存在了一年多的已知问题,在研究公开后依然没有官方回应,这本身也是开发者需要把防线掌握在自己手里的原因。
受影响的也不只是个人开发者。Apiiro 统计的 63 家机构大多是软件公司,其中不乏把生产数据库密码和云服务商管理员密钥写进命令里的人。对这些团队来说,一次泄露可能意味着整个生产环境的凭证都要轮换,成本远不止改几行配置。更麻烦的是,泄露的文件可能已经被 Fork、被镜像、被存档进各种数据集,删除原始仓库并不能收回已经扩散出去的副本。
同一周的另一桩事:Cursor 市场里的假扩展
几乎同一时间,Claude Code 的用户还遭遇了另一起安全事件,只是性质完全不同。10 月 29 日,Cursor 扩展市场里出现了被篡改的 Claude Code 扩展,版本 2.1.312 和 2.1.313,在市场上挂了约 11 个小时。篡改者往扩展里加了一个加载器:会在用户电脑上写入攻击者的 SSH 密钥(标注为 svc-telemetry),尝试开启 SSH 服务并建立反向隧道,同时把主机名、用户名、Git 邮箱、公网 IP 和环境变量名发往一台外部服务器。
Cursor 表示最多约 5000 名用户安装了被篡改的版本,并承诺直接联系他们。Anthropic 强调,被篡改的版本并非由 Anthropic 制作和发布,其自身系统没有遭到入侵,问题只出在 Cursor 市场的那份拷贝上。微软方面也确认,被篡改的版本从未出现在 Visual Studio Marketplace 或 npm 上。修复版本 2.1.314 已经发布,但研究人员提醒:升级到修复版本并不会自动清除已被写入的攻击者密钥和持久化配置,中招的机器需要手动清理。
这两件事要分开看:一件是 Claude Code 自身的功能设计导致密钥泄露,另一件是第三方市场被投毒。但它们共同指向同一个现实:AI 编程助手已经深度介入开发者的日常工作流,它接触的权限越来越多,出问题时的 blast radius(波及范围)也越来越大。过去泄露密钥需要开发者主动把 .env 提交上去,现在点一次“不再询问”就可能做到,门槛被大大降低了。
开发者自查清单:现在就做的七件事
如果你用 Claude Code,或者团队里有人在用,下面这份清单值得今天就过一遍:
- 查仓库里有没有 .claude/settings.local.json:用 GitHub 代码搜索或本地命令 git log –all — .claude/settings.local.json 检查,包括历史提交。文件一旦进过仓库,删掉当前版本是不够的,历史记录里还有。
- 把 .claude/ 写进项目 .gitignore:不要依赖 Claude Code 的全局忽略设置,项目级忽略才能跟着仓库走,保护所有协作者。
- 轮换所有可能泄露的密钥:如果你的 settings.local.json 曾经进过公开仓库,默认里面的密钥已经泄露,立即轮换数据库密码、API 密钥和令牌,不要先验证、后处理。
- 检查 Git 历史和 Fork:公开仓库一旦被 Fork,密钥就扩散到了别人手里,轮换是唯一可靠的补救。可以用 GitHub 的 secret scanning 告警和提交历史做交叉核对。
- 永远不要把密钥写进命令里:用环境变量、密钥管理工具或配置文件传参,不要把密码直接贴进要让 AI 执行的命令中。这是这次泄露最根本的教训。
- 审慎使用“不再询问”:对包含敏感信息的命令,只做一次性授权,不要点永久放行。定期打开 .claude/settings.local.json 检查里面到底存了什么。
- 检查 Cursor 用户的机器:如果 10 月 29 日在 Cursor 里安装或更新过 Claude Code 扩展,确认版本不是 2.1.312 或 2.1.313,检查 ~/.ssh/authorized_keys 里有没有名为 svc-telemetry 的陌生密钥,并运行 Cursor 官方提供的清理脚本。
清单上的每一步都不难,难的是养成习惯:把密钥当成绝不能进仓库的东西,而不是图方便时可以顺手贴进命令里的文本。
总结
Apiiro 11 月 5 日的研究显示,Claude Code 的“不再询问”功能会把含密钥的命令原文写进 .claude/settings.local.json,而这个文件在 1,122 个公开 GitHub 仓库副本中含有真实密钥,共计 1,379 个;把历史版本和共享设置文件算在内,总数是 2,539 个密钥、1,994 个仓库。研究方没有实际测试这些凭证是否有效,但至少有一家公司确认其泄露的密钥当时仍然有效。五分之一的泄露文件能逃过主流扫描工具的检测,而同一周 Cursor 市场被篡改的扩展事件又提醒我们,AI 编程工具链的安全边界正在变得越来越脆弱。对开发者来说,补救措施是明确的:查仓库、轮换密钥、把 .claude 写进项目 .gitignore,并且从此不再把密钥贴进任何一条要让 AI 执行的命令里。








- 最新
- 最热
只看作者