一次「不再询问」如何变成公开泄露

用 Claude Code 连数据库、调接口时,它拼出的命令里本来就带着配置文件里的密码或密钥。执行前工具会弹窗请求确认,本是安全护栏;但为减少重复弹窗,它提供了一个「Yes, and don’t ask again」(同意且不再询问)选项。一旦勾选,这条完整命令——连同里面嵌入的数据库密码、API 密钥——会被原样存进项目目录下的 .claude/settings.local.json,作为一条允许规则。这个文件没有被写进项目自己的 .gitignore,于是它跟着代码一起被推送到公开 GitHub,任何人都读得到。

规模有多大
1,379 条独立真实凭证的类型分布(当前文件,不含 Git 历史)数据库密码379Supabase 服务角色密钥122Supabase 账号令牌103SSH 登录(含 root)43GitHub/GitLab/npm 令牌42AWS 密钥23私钥6另有约 764 条为第三方服务 API 令牌与 AI 模型密钥(未在图中单列)。合并 Git 历史、共享配置与 Agent 对话记录后,全源总计 2,539 条真实凭证,散落 1,994 个仓库,牵出 63 家组织。
Apiiro 在公开 GitHub 当前含密文件中检出的 1,379 条独立凭证类型拆解

安全研究机构 Apiiro 在 11 月 5 日发布的研究报告里,对公开 GitHub 做了只读扫描:平台上共有 104,185 份 .claude/settings.local.json 副本(分布在 103,617 个仓库),其中 1,122 份(约 1.1%)含有真实密钥。把 Git 历史提交、团队刻意提交的共享 settings.json、以及 Agent 对话记录合并计算后,总计 2,539 条真实凭证散落在 1,994 个仓库,牵出 63 家组织——从学生社团、创业公司、软件外包商到老牌厂商都在列。值得注意的是,在能追溯到含密文件的 1,105 个仓库里,有 539 个的改动提交由标注 Claude 共同作者的 commit 完成,涵盖 Sonnet 4.5 到 Opus 5.5 等近期模型。

泄露的到底是什么

在确认含密的当前文件里,共 1,379 条独立凭证,超过三分之一能直接打开数据库:379 条数据库密码、122 条 Supabase 服务角色密钥、103 条 Supabase 账号令牌;此外还有 43 条 SSH 登录凭据(部分包含服务器 root 密码)、42 条 GitHub/GitLab/npm 令牌、23 条 AWS 密钥与 6 条私钥。Apiiro 举的典型案例触目惊心:某数据库厂商自己的管理员级云密钥、一套生产环境 Azure Postgres 密码、一个 Square 生产令牌、一家医疗记录数据库的所有者密码。研究人员通知相关方时,至少有一家确认其密钥在被发现时仍然有效。

工具设计的争议与 Anthropic 的回应

问题根源在于 Claude Code 把用户的授权操作持久化到项目本地文件,而该文件默认保存完整命令原文。Claude Code 在创建文件时会把它加进开发者的全局 git 忽略清单,覆盖常见场景;但它不写进项目自身的 .gitignore,于是一个后来才变成仓库的文件夹、在另一台机器上克隆的项目、或早已被 commit 过的文件,都会失去这层保护。在 Apiiro 对比的 16 款编码智能体中,Claude Code 被确认默认将完整命令写入项目文件。事件发酵后,Anthropic 的 Claude Code 负责人 Boris Cherny 于 11 月 7 日在 Hacker News 回应,称团队历史上没做过密钥擦除,但正在评估能做什么来防止这类问题,并列举了若干候选方向:让 auto 模式拦下这类情况、内置基础密钥扫描。他也建议用户改用 auto 模式、并开启 GitHub 等平台提供的密钥扫描。

给开发者的处置顺序

Apiiro 给出的建议很直接:先轮换凭据,再清理。具体动作包括——在 GitHub 组织内搜索 .claude/settings.local.json 与 settings.json,每个命中都是此刻任何人都能读到的文件;检查每个仓库的 Git 历史(哪怕文件今天已删,fork 与克隆里还压着旧版本,其中 211 个分叉携带着同样的密钥);在本机找出每份文件副本,逐条检查允许列表里是否嵌着密码、令牌、密钥或连接串;最后把命令里的明文换成变量、用模式匹配而非精确命令做授权。Gitleaks、TruffleHog 这类扫描器对藏在命令参数里的密码存在盲区,不能全靠它们。

信息来源