Claude Code“不再询问”选项致 1122 个 GitHub 文件泄露密码
安全研究机构 Apiiro 发现,Claude Code 的“Yes, and don't ask again”选项会把配置文件中的数据库密码、云密钥、API Token 等敏感凭据写入命令并持久化保存,导致 1,994 个公开 GitHub 仓库中泄露 2,539 条真实密钥,涉及 63 家组织。Anthropic Claude Code 负责人 Boris Cherny 已回应称团队正在研究防护方案,计划加入自动模式拦截与基础密钥扫描。
报道正文
本文目录12 个章节
11 月 8 日更新:Anthropic 的 Claude Code 负责人作出回应。 Boris Cherny 于 11 月 7 日在 Hacker News 上作出回应,并参与了整个周末的讨论。他表示团队正在“研究可以采取哪些措施来防止这种情况”,并列举了计划进行原型验证的方案:“确保自动模式能够捕获这种情况,内置基础的密钥扫描”,当一位读者指出,在自动模式下询问敏感命令时也可能发生同样的问题,他回答说“发现得好”。完整回应见下文。
Apiiro 的研究在 1,994 个公开 GitHub 仓库中发现了 2,539 个真实密钥:数据库密码、云密钥、API 令牌、SSH root 登录凭据。其中包括:某数据库厂商自己的管理员级云密钥、一个生产环境的 Azure Postgres 密码、一个 Square 生产令牌,以及一个医疗记录数据库的所有者密码。大多数属于个人开发者。共有 63 个组织受到影响,从学生团体到初创公司、软件代理机构和成熟厂商都有。其中一家已确认其密钥曾处于有效状态。
让 Claude Code 检查数据库或调用 API 时,它提出的命令会带上你配置文件中的密钥。它在运行前会先询问。选择“是,且不再询问”后,它就会把那条确切的命令(包括密钥)保存到项目文件夹内的 .claude/settings.local.json 中。仓库中没有任何标记表明该文件是私有的,因此它会随其余代码一起被提交。
在 GitHub 上 104,185 份该文件的公开副本中,有 1,122 份包含真实密钥。我们又在 git 历史、团队有意提交的共享 settings.json,以及保存在仓库中的智能体聊天记录里,发现了另外 1,160 个密钥。
检查你是否受到影响
它是公开的吗? 在你的 GitHub 组织中搜索 .claude/settings.local.json 和 .claude/settings.json。每一个搜索结果都是现在任何人都能读取的文件。
它是否曾被提交过? 检查每个仓库的 git 历史中是否存在该文件,即使它如今已被删除。如果历史中有它,那么每个 fork 和 clone 也都有。
里面有什么? 找到你机器上该文件的每一份副本,并阅读其允许列表。每个条目都是你批准过的命令,其中包含你输入的任何内容:查找密码、令牌、密钥和连接字符串。
发现了问题: 先轮换,再清理。
密钥是如何进入设置文件的
开发者的机器上存着各种密钥:配置文件里的数据库连接字符串、本地安装中的云密钥、.env 里的 API token。当你让 Claude Code 排查 staging 环境登录失败的原因,或者执行一次迁移时,它提出的命令就会带上那个密钥,因为不带就没法执行。Claude Code 在运行 shell 命令前会先征求确认,一个会话里要问很多次。到第十次打断时,大多数人就不再细看命令了,而密钥可能只是长长一行里的一个词:

选择“Yes, and don't ask again”,它就会运行该命令,并向项目文件夹里的 .claude/settings.local.json 添加一条权限规则,这样以后就不再询问。这条规则就是命令字符串本身:

这是 Claude Code 自身的行为,而不是模型的行为:Anthropic 最新的模型同样如此,我们用 Opus 5.5 和 Fable 5.1 复现了这一点。
这个文件本应只留在开发者自己的机器上,Claude Code 也试图让它保持如此。当它在 git 仓库内创建该文件时,会把它加入开发者的全局 git 忽略列表。这覆盖了常见情况,但覆盖不了后来才变成仓库的文件夹、另一台机器上的克隆,或者已经被人提交过的文件。这条规则从不会写进仓库自己的 .gitignore,所以没有任何东西随项目一起传播来保护它。
Claude Code 确实会注意到该文件已被 git 跟踪:权限文档说,被跟踪的副本会被视为由仓库提供,其调试日志会记录“is tracked in the index; gitignore rules do not apply to tracked files.”。用户不会被告知这一点,而下一次批准会被追加到那个被跟踪的文件里。
Claude 常常会自己提交这个文件。在我们追踪到的 1,105 个含真实密钥的仓库中,有 539 个仓库里由 Claude 共同署名的提交改动过该文件。这些提交涉及所有近期模型,从 Sonnet 4.5 到 Opus 5.5。Claude Code 的提交指令告诉模型不要提交 .env 或 credentials.json,但它自己的设置文件不在这个列表上。
谁暴露了
有 63 个组织在公开的允许列表中持有真实密钥。最确凿的案例都位于 .claude/settings.local.json,且每个都在固定的提交上核查过:
| 组织 | 暴露内容 |
|---|---|
| 数据库厂商 | 其自有云 API 密钥,具备管理权限且无过期声明,以及集群主机 |
| B2B 初创公司 | 生产环境 Azure Postgres 密码 |
| 软件代理机构 | Square 生产环境访问令牌 |
| 开源项目(超过 1,000 星) | OpenAI 格式 API 密钥 |
| 开源项目 | npm 令牌 |
| IT 服务公司(医疗记录应用) | 该应用云 Postgres 数据库的所有者密码 |
| 支付初创公司 | postgres 角色的 Postgres 密码 |
这些群体涵盖学生与黑客松团队、初创公司、软件代理机构和 IT 服务公司。少数是成熟厂商,通过其自身的演示和研讨会仓库暴露出来。没有人有意发布密钥。密钥出现在一条命令中,命令被批准,文件便连同其他内容一起被提交了。
允许列表中还包含服务器登录凭据:43 个公共服务器的 SSH 凭据,其中一些是 sshpass 命令中的 root 密码。例如,某大学的仓库永久批准了一条指向公共服务器的 root SSH 命令。
数量有多少
公共 GitHub 上有 104,185 份 .claude/settings.local.json 副本,分布在 103,617 个仓库中。1,122 个文件(1.1%)包含真实密钥:要么是已知提供商格式的密钥,要么是紧邻公共主机名的密码或令牌。它们合计包含 1,379 个不同的密钥:636 个提供商密钥和 743 个公共主机的密码或令牌。
超过三分之一可直接打开数据库:379 个数据库密码和 122 个 Supabase service-role 密钥。另有 103 个是 Supabase 账户令牌,可控制账户中的每个项目。其余大多是第三方服务和 AI 模型的 API 令牌,外加 43 个 SSH 登录凭据、42 个 GitHub、GitLab 和 npm 令牌、23 个 AWS 密钥和 6 个私钥。

大型允许列表推高了这一比例。超过 8 KB 的文件中,每十个就有一个包含真实密钥,而在小于 500 字节的文件中,这一比例不到五百分之一。开发者点击“不再询问”的时间越长,文件中积累的内容就越多。

这些文件仍然存在:截至 2026 年 11 月 2 日,每一个都还留在其仓库的默认分支上,而且大多数已经在那里存在了很长时间。在包含真实密钥的仓库中,该文件首次提交时间的中位数为 217 天前。有 118 个仓库超过一年。分叉会复制它们:74 个仓库的 211 个分叉携带相同的密钥。
删除文件并不能解决问题。该文件的早期版本在 509 个仓库中持有 734 个真实密钥,这些密钥不出现在任何当前副本中,通常是因为文件已被删除。
计入该文件的历史记录、共享设置文件和 agent 转录(见后续章节),总计为 1,994 个仓库中的 2,539 个不同的真实密钥。
密钥扫描器漏掉了什么
通用密钥扫描器会漏掉其中许多。我们对全部 104,185 个文件运行了 gitleaks 和 TruffleHog。在 1,122 个包含真实密钥的文件中,gitleaks 标记了 564 个,TruffleHog 标记了 643 个;有 215 个两者均未标记。
真正的缺口在于命令中的密码。扫描器寻找的是密钥格式:提供商前缀、一长串随机字符串。而写在 PGPASSWORD=、sshpass -p 或 mysql -p 之后的密码,或者 curl 调用中的 bearer 请求头,不过是普通命令行里的普通单词,这两个工具大多会直接放行。

这个问题的影响不止于这一个文件。只要 agent 记录了它执行过的内容,同样的“命令中带密码”模式就会出现:对话记录、记忆文件、交接笔记,而针对密钥格式调优的扫描器在所有这些地方都会漏掉它。
不止一个文件
允许列表是最明显的案例,但 agent 还会把密钥写进开发者会提交的其他文件里。
| 文件 | 已检查 | 含真实密钥 |
|---|---|---|
| 共享的 .claude/settings.json | 全部 76,011 个 | 298 个文件 |
| Agent 聊天记录(.specstory、aider、Cursor 导出) | 2,523 个 | 87 个仓库中的 120 个文件 |
| Agent 记忆文件(MEMORY.md 及类似文件) | 1,200 个 | 9 个仓库 |
| 交接与部署说明 | 2,095 个 | 33 个文件 |
| VS Code Copilot 自动批准设置 | 173 个 | 9 个仓库 |
团队是故意提交共享设置文件的,而其中的大多数密钥都以精确命令行形式存在于允许规则中。带有密钥的交接备注中,有三分之一是智能体自己写的。
该文件的泄露范围也不止于 GitHub。在 31,053 个 Hugging Face Spaces 中,有 126 个包含 .claude/settings.local.json,其中一个的允许规则里含有数据库服务密钥和用户密码。在 GitLab.com 上,我们检查的 69 个公开副本中有 2 个含有真实密钥,其中包括一个 GitLab 访问令牌。
导致泄露的习惯在哪里都一样:把密钥输入到命令中,然后由智能体记录下来。
在开发者机器上
这些文件大多从未到达 GitHub。它们留在开发者的机器上,但这并不意味着它们安全。允许列表就是项目文件夹中的纯 JSON。
恶意软件已经在从开发者机器上批量收集凭据。2025 年 9 月,Shai-Hulud npm 蠕虫下载了 TruffleHog,并在受害者的文件上运行。该扫描器在 1,122 个文件中标记出 643 个含有真实密钥的文件。三周前,恶意 Nx 包指示开发者自己的 Claude Code 和 Gemini CLI 在磁盘上搜索密钥。
该文件也可以不经过 git 而离开:在已发布的 npm 包中、在使用复制命令构建的 Docker 镜像中、在 zip 归档中或在同步文件夹中。而一个曾被批准的密钥会一直留在文件中,直到有人删除该规则,哪怕命令早已运行完毕。
先前工作
本文补充了 GitHub 上大规模密钥泄露的完整计数、组织案例、扫描器盲区,以及携带相同密钥的其他智能体文件。Claude Code 用户自 2025 年 8 月起就在 GitHub issue 中报告了这一机制(#5544、#11982、#13106、#91270)。没有一个得到 Anthropic 的回复,其中三个因不活跃或重复而被自动关闭。ironPeak 于 2026 年 2 月在自己的仓库中发现了同一文件,并在 100 个仓库的样本上测得,2.4% 带有 AI 配置文件夹的仓库在历史记录中携带密钥。Lakera 在 4 月发现 30 个 npm 包中的 33 个此类文件含有凭据。
该怎么做
开发者:
- 如果文件已被仓库跟踪,请用
git rm --cached .claude/settings.local.json取消跟踪,并将其添加到该仓库自己的 .gitignore 中。 - 轮换该文件曾经持有过的每一个凭据。删除文件并不会清除 git 历史、fork 或克隆。
- 即使该文件从未被提交,也要打开它并删除每一条包含密钥的规则。
- 停止在命令中直接输入密钥。改为从你使用的任何密钥管理器中以 DB_URL,而不是密钥本身。
- 批准模式(如
Bash(npm run:*)),而不是字面命令。
安全团队:
- 将 agent 文件夹——.claude/、.cursor/、.gemini/、.specstory/、agent 记忆文件——视为可能包含密钥的内容,就像 .env 一样,无论是在笔记本电脑上还是在仓库中。
- 将它们加入 pre-commit 和 CI 的密钥扫描,包括历史记录。确保扫描器能捕获命令中的密码(PGPASSWORD=、sshpass -p、mysql -p、bearer 头),而不仅仅是服务商密钥格式。
- 将 .claude/settings.local.json 加入你组织的 .gitignore 模板。
- 优先排查与公共主机配对的凭据:这些才是真正能提供访问权限的。
Anthropic 的 Claude Code 负责人回应
我们在发布前与 Anthropic 分享了这项研究。文章上线后,Anthropic 的 Claude Code 负责人 Boris Cherny 于 11 月 7 日在 Hacker News 上作出回应,并在周末发布了十条评论。
从历史上看,Claude Code 并没有做密钥清理(这方面有很多好工具),但我们正在研究能做些什么来防止这种情况。
关于方法:
有几种可能的方法:确保自动模式能捕获这种情况、内置基本的密钥扫描,以及其他一些想法。我们打算先原型验证其中几种,以便在正式发布前更好地理解权衡。
当一位读者指出,在自动模式下询问敏感命令时也可能发生同样的情况:
是的,说得好。我们正在思考能做些什么来改进这一点(欢迎提出想法)。
他还表示,Claude Code 在创建该文件时会将其加入 gitignore,因此在他看来,那些被暴露的副本是手动创建并提交的;他推荐使用自动模式而非权限规则;并建议启用 GitHub 和其他托管平台提供的密钥扫描功能。
披露
我们于 2026 年 11 月 2 日和 3 日向各组织案例的所有者报告了每个案例。我们还通过 Anthropic 要求的披露渠道以及其他几个渠道通知了 Anthropic。
方法与局限
采集。 所有数据均来自 2026 年 11 月 1 日至 3 日对默认分支进行的只读 GitHub 代码搜索和提交搜索。代码搜索每次查询最多返回 1,000 条结果,因此我们按文件大小拆分搜索,直到每个分片都低于上限。这样共列出 103,617 个仓库中的 104,185 个 .claude/settings.local.json 文件,以及 76,011 个共享的 settings.json 文件,我们全部下载了。文件历史覆盖 43,120 个仓库,包括所有提交中提到删除、取消跟踪、脱敏或轮换该文件的仓库,因此历史计数只是下限。分叉:每个含有真实密钥的仓库的所有分叉。转录记录、记忆文件、交接笔记和 Copilot 设置是通过搜索密钥前缀和连接字符串找到的;表格给出了我们检查的数量。我们根据文档比较了 16 种编码代理存储审批的方式;Claude Code 是唯一被确认默认会将完整审批命令写入项目文件的代理。
分类。 我们使用密钥扫描器所用的两类检测器。提供商模式匹配已知的密钥格式:OpenAI、Anthropic、AWS、GitHub、npm、Supabase、Stripe、Slack 等。通用密钥是格式未知的密码和令牌;只有当同一行上存在公共主机时,我们才将其计入,例如连接字符串中,或 psql -h 之前的 PGPASSWORD=。随后规则会移除已知的误报:占位符、常见默认密码、本地和私有主机、设计上就公开的密钥(Supabase anon 密钥、Firebase Web 配置)、本地 Supabase 演示密钥、过期令牌,以及内置校验和验证失败的 GitHub 和 npm 令牌。所有剩余的 2,774 个不同值,均由一位依据书面评分标准工作的独立 LLM 审核员在其掩码上下文中逐一审核。只有当规则和审核结果一致时,该值才被计为真实密钥:所有来源合计 2,539 个。记忆文件、交接笔记和 Copilot 设置仅由规则分类。gitleaks 和 TruffleHog 在未验证的情况下运行。
局限。 未使用或测试任何凭据,也未联系任何主机。“真实密钥”指符合提供商格式或指向公共主机的凭据,而非已知有效的凭据。每个组织案例均在固定提交的链接上进行了核查。