把数据库密码锁进本地 .env 文件,再把 .env 写进项目的 .gitignore,是程序员维持了十多年的安全默契。但应用安全公司 Apiiro 在 2026 年 11 月 5 日发布的报告打破了这层默契——他们在 1,994 个公共 GitHub 仓库里筛出了 2,539 个真实密钥,波及 63 家机构,其中 1 家已确认密钥处于活跃状态。把这些生产环境密码捅到公网上的,正是开发者每天用来写代码的命令行智能体 Claude Code,而且近一半的泄漏文件是 Claude 自己亲手 git commit 上去的。
这批暴露的凭证里,有数据库厂商自家的无期限管理级云 API 密钥、B2B 初创公司的生产环境 Azure Postgres 密码、Square 生产环境 Token、医疗记录应用的云数据库 Owner 密码,甚至还有 43 个公网服务器 SSH 凭证(部分为 sshpass 命令里的 Root 密码,一所高校仓库就永久批准了一条连接公网服务器的 Root SSH 命令)。需要厘清一个口径,Apiiro 处于合规并未向目标主机实际发起连接测试,报告里的真实密钥指的是通过规则过滤与独立 LLM 审查员在掩码上下文中双重确认的高置信度凭证。
在 GitHub 公开可见的 104,185 个 .claude/settings.local.json 文件副本里,有 1,122 个文件(占比 1.1%)直接躺着 1,379 个独立密钥,涵盖 379 个数据库密码、122 个 Supabase 服务角色密钥和 103 个可控制账户下所有项目的 Supabase 账户 Token。加上 Git 历史记录、团队故意提交的共享 settings.json 以及仓库里保存的代理聊天记录,额外抓出的 1,160 个密钥共同构成了 2,539 这个总盘子。
一次偷懒点击引发的链式失守
密码是怎么从受保护的 .env 跑到全世界面前的?导火索是命令行智能体为了减少弹窗打扰而设计的权限持久化机制。

当你让 Claude Code 去排查测试服登录失败或者跑一次数据库迁移,它必须先读取你本地 .env 里的凭证,拼装成一条带明文密码的 Shell 命令。每次执行前它会弹窗询问,一旦你嫌烦点下 Yes, and don't ask again(是,不再询问),Claude Code 就会把整条命令字符串一字不差地作为白名单规则,写进项目文件夹下的 .claude/settings.local.json。点得越久,文件越肥;体积超过 8KB 的配置文件里,每 10 个就有 1 个藏着真密钥。
Anthropic 并非毫无防范,只是选错了防线位置。Claude Code 首次在 Git 仓库里生成这个本地设置文件时,会把它加进开发者本机的全局忽略列表(global git ignore),而不是写进项目自带的 .gitignore。
这种单机绑定的设计在真实协作里到处是漏勺。如果开发者先在普通文件夹里用 Claude 调试代码、事后才执行 git init,或者把仓库克隆到另一台没配过全局忽略的机器上,又或者有人已经把文件提交进了版本库,全局忽略瞬间失效。更黑色幽默的是,当开发者习惯性地让 AI 帮自己打包提交代码时,Claude 根本不知道这个文件里存着它刚才拓印下来的明文密码。在 Apiiro 追踪的 1,105 个含密仓库里,有 539 个仓库的泄漏文件是由 Claude(涵盖 Sonnet 4.5、Opus 5.5 及 Fable 5.1 等模型)作为共同作者(co-authored)亲自提交上去的。
你可能会想,既然如此,在项目里建个 .claudeignore 把 .env 屏蔽掉不就行了?这正是最多开发者踩坑的盲区。Claude Code 官方文档明确写着,.claudeignore 实际上无效;要想阻止代理读取敏感文件,必须在配置里显式编写 Read(./.env) 这类拒绝规则。哪怕配了这条规则,也只能拦住 Claude 自己的内置读取工具,一旦它调用 Python 脚本等任意子进程在内部直接打开文件,应用层规则照样失灵,完整隔离只能靠操作系统级沙箱。
被机器人关掉的预警与失灵的扫描器
早在 2025 年 8 月 11 日,就有开发者在 GitHub 上给 Claude Code 提交了 Issue #5544,明确指出权限规则会把完整命令连同内嵌的 API 密钥以明文形式保存下来(后续还有 #11982、#13106、#91270 等多个同类反馈)。但这些预警没有得到 Anthropic 的任何实质回复,Issue #5544 在 2026 年 1 月 3 日因为不活跃被机器人自动打上 closed as not planned 标签关掉了。安全机构 ironPeak 在 2026 年 2 月也披露过自家仓库因完全相同的路径发生泄漏;直到 Apiiro 在 11 月 2 日至 3 日向涉事组织发出通知,截至 11 月 7 日仍未见 Anthropic 对此做出公开声明或修复确认。

《韩非子》里讲,千丈之堤,以蝼蚁之穴溃。在 AI 编程工具狂飙突进的这两年,厂商把绝大多数精力砸在了模型上下文长度和代码生成准确率上,却对工程底座里最基础的凭证脱敏视而不见。对比同行就会发现,这根本不是什么无解的技术难题:
| 编程代理工具 | 权限持久化机制 | 敏感凭证隔离边界 |
|---|---|---|
| Claude Code | 默认将批准的完整明文命令写入项目 .claude/settings.local.json | 仅写入本机全局 gitignore,无项目级默认保护 |
| GitHub Copilot CLI | 支持单次或仅限当前会话(session-scoped)授权 | CLI 权限标志不写入持久化文件 permissions-config.json |
| Cursor | 支持在 .cursor/permissions.json 配置命令或前缀白名单 | 官方文档明确声明白名单仅作便利控制而非安全边界 |
AI 把静态密钥变成了动态命令快照,旧安防瞬间成了摆设。
比厂商冷处理更棘手的,是现有 DevSecOps 安全工具链的代际失灵。Apiiro 把行业标准的密钥扫描器 gitleaks 和 TruffleHog 拉出来跑了一遍全部 104,185 个文件:面对 1,122 个真含密文件,gitleaks 只报出了 564 个,TruffleHog 报出了 643 个,有 215 个文件(占五分之一)连这两个主流扫描器都没认出来。
原因在于传统扫描器是按静态特征码设计的,它们擅长抓 sk- 开头的高熵随机字符串。但 AI 代理写进白名单、聊天记录(.specstory、aider、Cursor 导出记录)和交接笔记里的,大量是跟在 PGPASSWORD=、sshpass -p、mysql -p 或者 curl 请求头后面的普通文本密码。在扫描器眼里,这只是一行普通命令里的普通单词,直接放行。
- 风险.就算你的仓库从没推上 GitHub,留在笔记本硬盘里的明文白名单同样是定时炸弹——2025 年 9 月爆发的 Shai-Hulud npm 蠕虫已经在受害者电脑上自动下载 TruffleHog 批量搜刮本地凭证,而再早三周出现的恶意 Nx 软件包,甚至直接下指令让开发者电脑上的 Claude Code 和 Gemini CLI 自己全盘搜索密钥。
当智能体接管终端, .claude/、.cursor/、.gemini/ 和各类 MEMORY.md 已经变成了和 .env 一样高危的储密容器。现在去搜一遍你团队仓库的 Git 历史(哪怕文件今天已经删了,记录还在,Apiiro 就在已删除文件的历史版本里挖出了 734 个真密钥),把命令里的硬编码密码全部换成 $DB_URL 这样的环境变量引用,是眼下唯一能立刻止血的动作。Anthropic 什么时候把默认保存完整命令字串的逻辑改掉,才是这场泄漏真正的终点。
