MemoryLake
返回全部文章
News2026 年 11 月 11 日·13 分钟阅读

Claude Code settings.local.json 正在向公共代码库泄露密钥 —— 为什么“不再询问”会保存整个命令,以及如何清理已提交的代码库 (2026)

你让 Claude Code 检查为什么暂存环境登录失败。它建议执行一条数据库命令,该命令需要密码,而你选择了停止再次询问的选项。命令运行了,问题解决了,你继续后续工作。

但那个授权并没有消失。Claude Code 将其作为权限规则写入了项目中的一个文件,而该规则本身就是命令,包含密码。2026 年 11 月 5 日,安全公司 Apiiro 发布了关于后续影响的研究:“Apiiro 的研究在 1,994 个公共 GitHub 代码库中发现了 2,539 个真实的密钥:数据库密码、云密钥、API 令牌、SSH root 登录信息。”

本指南解释了该文件是什么、为什么密钥会出现在其中、为什么 Claude Code 自身的保护并不总是有效、Anthropic 目前的说法,以及如何检查和清理你的代码库。它还涵盖了 Apiiro 研究中超出单个文件的部分:智能体也会在其他地方记录它们运行的内容,包括 memory 文件。

如果你想更全面地了解 Claude Code 在会话之间保存在你机器上的内容,我们的 Claude Code 自动 memory 是什么 指南涵盖了 memory 文件夹。本文则侧重于设置文件及其内部的授权规则。

什么是 settings.local.json

Claude Code 从多个文件中读取设置。Anthropic 的设置文档将项目本地设置描述为 .claude/settings.local.json,用于“仅限你在此项目中使用”。其预期用途是针对单个项目的个人覆盖,以及在共享前的测试。

你不需要手动创建它。文档指出,Claude Code 会在“你第一次对权限提示给出长期授权”时写入 .claude/settings.local.json。权限文档详细说明了这对 shell 命令意味着什么。当你选择停止 Claude Code 再次询问并永久保存授权时,“例如对于 Bash 命令或 WebFetch 域名,Claude Code 会将规则保存到 git 代码库根目录下的 .claude/settings.local.json 中”。

同一页面中的两个细节至关重要。Bash 授权是“每个代码库和每个命令永久有效”的。并且该规则适用于“该代码库中任何位置的未来会话,包括在子目录和工作树(worktrees)中启动的会话”。你给出的一次授权会一直生效,并一直存在于文件中,直到有人将其删除。

为什么密钥会出现在文件中

Apiiro 的报告梳理了这一过程。“要求 Claude Code 检查数据库或调用 API,它建议的命令会携带来自你配置文件的密钥。它在运行前会进行询问。”密钥必须包含在命令中,因为没有它命令就无法运行。

接着是授权。Apiiro 写道,当你选择“不再询问”选项时,“它会运行命令并将权限规则添加到项目文件夹中的 .claude/settings.local.json,这样它就不会再问了。该规则就是命令字符串本身”。

权限规则旨在描述允许 Claude Code 运行的内容。当获得授权的命令中输入了密码、令牌或连接字符串时,规则会以明文形式存储该值。

Apiiro 表示这是工具的行为,而不是某个模型的怪癖:“这是 Claude Code 自身的行为,而不是模型的:它在 Anthropic 最新的模型上也会发生,我们在 Opus 5.5 和 Fable 5.1 上都复现了这一点。”

为什么 Claude Code 自身的保护并不总是有效

Claude Code 确实尝试将该文件排除在 git 之外。设置文档称,“Claude Code 第一次在尚未忽略该文件的 git 代码库中写入文件时,它会将 **/.claude/settings.local.json 添加到你的全局 git 排除文件中,因此该文件在每个代码库的提交中都会被排除。”

关键词是“全局”。该排除项存在于你机器上的 git 配置中,而不是代码库中。Apiiro 描述了这个漏洞:“这涵盖了常见情况。但它不涵盖后来变成代码库的文件夹、另一台机器上的克隆,或者某人已经提交的文件。”并且:“该规则从未进入代码库自身的 .gitignore,因此没有任何东西随项目移动来保护它。”

对于你自己创建的文件,还有一个记录在案的例外。设置表显示 Claude Code “在创建文件时将其排除在 git 之外;如果你手动创建它,请自行将其添加到 .gitignore”。

一旦文件被追踪,Claude Code 会改变处理方式,但仍会继续写入。权限文档称:“当文件在 git 中被追踪,或者 .claude 是一个符号链接时,Claude Code 会将其视为代码库提供的文件,并保留其规则,直到你信任该文件夹。”Apiiro 补充说,用户并没有被告知这一点,“并且下一次授权会被追加到被追踪的文件中。”

Apiiro 还追踪了是谁提交了该文件:“在我们追踪的 1,105 个包含真实密钥的代码库中,有 539 个是由 Claude 共同署名的提交修改了该文件。”其解释是 Claude Code 的提交指令列出了像 .env 和 credentials.json 这样的文件,但“它自己的设置文件不在该列表中”。

Apiiro 的发现

这些数据来自 2026 年 11 月 1 日至 3 日对默认分支进行的只读 GitHub 代码和提交搜索。Apiiro 表示未测试任何凭据:“没有使用或测试任何凭据,也没有联系任何主机。”

主要统计数据:

  • 文件本身。 “在 GitHub 上的 104,185 份该文件公共副本中,有 1,122 份包含真实密钥。”
  • 当前副本中的不同密钥。 “它们总共包含 1,379 个不同的密钥:636 个服务商密钥和 743 个公共主机的密码或令牌。”
  • 数据库访问。 Apiiro 统计了 379 个数据库密码和 122 个 Supabase service-role 密钥,外加 103 个 Supabase 账户令牌。
  • 服务器登录。 “43 个公共服务器的 SSH 凭据,其中一些是 sshpass 命令中的 root 密码。”
  • 组织。 “63 个组织在公共允许列表中持有真实密钥。”Apiiro 表示大多数密钥属于个人开发者。

两项发现解释了为什么仅删除当前文件是不够的。首先,这些文件往往存在很长时间:“在包含真实密钥的代码库中,中位文件在被发现前 217 天就已首次提交。”其次,历史记录保留了它们:“旧版本的文件包含 734 个真实密钥,分布在 509 个代码库中,这些密钥在当前副本中已不存在,通常是因为文件已被删除。”

文件越大,包含的内容越多。Apiiro 写道:“超过 8 KB 的文件中,每十个就有一个包含真实密钥,而 500 字节以下的文件中,这一比例不到五百分之一。”

为什么密钥扫描器会漏掉很多密钥

你可能期望密钥扫描器能捕获这些。Apiiro 对每个文件运行了 gitleaks 和 TruffleHog。“在 1,122 个包含真实密钥的文件中,gitleaks 标记了 564 个,TruffleHog 标记了 643 个;有 215 个未被任何一个标记。”

原因是密钥的形态。扫描器寻找已知的密钥格式。而在 PGPASSWORD=、sshpass -p 或 mysql -p 之后输入的密码看起来就像普通命令行中的普通单词。Apiiro 的总结是:“缺口在于命令内部的密码。”

不仅仅是一个文件

这是研究中超出权限设置的部分。Apiiro 写道:“同样的‘命令中包含密码’模式出现在智能体记录其运行内容的任何地方:转录文本、memory 文件、交接笔记,而针对密钥格式调整的扫描器在所有这些文件中都会漏掉它。”

其列出的其他文件包括:

  • 共享的 .claude/settings.json。 检查了所有 76,011 份公共副本,298 个文件包含真实密钥。团队是有意提交此文件的。
  • 保存在代码库中的智能体聊天转录。 检查了 2,523 份,涉及 87 个代码库中的 120 个文件。
  • 智能体 memory 文件 (MEMORY.md 及类似文件)。 检查了 1,200 份,涉及 9 个代码库。
  • 交接和部署笔记。 检查了 2,095 份,涉及 33 个文件。Apiiro 补充道:“包含密钥的交接笔记中有三分之一是由智能体本身编写的。”

memory 文件的数量虽然较少,但模式是一样的。智能体记录的关于其操作的任何内容都可能携带命令中的任何信息。如果你在智能体维护的文件中保留项目上下文,这些文件应受到与设置文件相同的关注。

默认情况下,Claude Code 将会话转录存储在你的主目录 ~/.claude/projects 下。我们的 查找 Claude Code 会话历史 指南涵盖了它们的存放位置和保留时间。Apiiro 的转录统计涵盖了人们保存到代码库中的各种工具的导出内容。

在你的机器上也是如此

大多数副本从未到达 GitHub,Apiiro 认为这并不意味着它们是安全的。“允许列表在每个项目中都是相同路径下的纯 JSON,而且其中的大多数密钥就放在它们所开启的主机旁边。”它还指出,该文件可以在没有 git 的情况下流出,“在发布的 npm 包、使用 copy 命令构建的 Docker 镜像、zip 压缩包或同步文件夹中。”

如果你在一个代码库的多个检出(checkouts)中工作,该文件位于一个固定位置。文档称,在工作树中,Claude Code “使用主检出根目录下的文件”。我们的 Claude Code 工作树是否共享 memory 指南解释了工作树之间还共享哪些内容。

Anthropic 的回应

Apiiro 表示在发布前已与 Anthropic 分享了这项研究。在 11 月 8 日的更新中,Apiiro 报告称 Claude Code 的负责人于 11 月 7 日在 Hacker News 上做出了回应。

根据 Apiiro 的更新,他写道团队正在“研究我们可以做些什么来防止这种情况”,并列出了计划进行原型设计的方案,“确保自动模式能捕获此类情况,内置基础密钥扫描”。Apiiro 还报告称,在他看来,暴露的副本是手动创建并签入的,他建议使用自动模式而非权限规则,并建议使用 GitHub 和其他托管商提供的密钥扫描功能。

截至 2026 年 11 月 10 日发布的 Claude Code 版本,发行说明中尚未描述授权保存方式的变更。请将此视为一个未解决的问题,并在依赖任何修复程序之前检查变更日志。

人们首先尝试的方法

删除文件并提交删除。 这删除了当前副本。但它不会删除历史记录、分支或克隆,而 Apiiro 正是在这些地方发现了 734 个在当前副本中不存在的密钥。

假设全局排除保护了每台机器。 它只保护了 Claude Code 写入它的那台机器。新的克隆、CI 运行器或后来变成代码库的文件夹并没有这个排除项。

仅依赖密钥扫描器。 Apiiro 测试的两个扫描器都漏掉了很大比例的文件,因为命令内部的密码看起来不像密钥。

一次又一次地授权相同的长命令。 每次长期授权都会添加一条字面规则,Apiiro 发现较大的文件包含密钥的可能性要大得多。

修复方案:检查、轮换,然后清理

第 1 步:查找所有副本

在你的 GitHub 组织中搜索 .claude/settings.local.json 和 .claude/settings.json。然后检查每个代码库的 git 历史记录中是否存在该文件,即使它现在已经消失。在你自己的机器上,找到每个副本并阅读其允许列表。在 Claude Code 内部,/permissions 会列出你的规则以及每条规则来源的设置文件。

第 2 步:先轮换,后删除

Apiiro 的顺序是“先轮换,后清理”。任何曾经出现在文件中(无论在哪个提交中)的凭据都应被视为已泄露。删除文件并不能清除历史记录、分支或克隆。

第 3 步:取消文件追踪并保护代码库

如果文件已被追踪,Apiiro 建议使用 git rm --cached .claude/settings.local.json 取消追踪,并将其添加到代码库自身的 .gitignore 中。这样,保护措施就会随项目移动,而不仅仅留在你的机器上。

第 4 步:改变授权方式

删除所有包含密钥的规则,即使是在从未提交的文件中。然后停止在命令中输入密钥。通过变量名引用它们,这样规则记录的是名称而不是值。授权模式(patterns)而不是字面命令:文档中的示例 Bash(npm run *) 可以匹配 npm run build 和 npm run test --watch。要注意模式的宽泛程度,因为文档指出第一个 * 之前的所有内容才是限制规则的关键。

第 5 步:将智能体文件视为敏感文件

将 .claude/、保存的转录文本、交接笔记和智能体 memory 文件添加到你的 pre-commit 和 CI 密钥扫描中,包括历史记录。确保扫描器会检查命令内部的密码,而不仅仅是密钥格式。

在 MemoryLake 中设置

Apiiro 的发现归结为一个习惯:智能体记录了它所做的事情,而你输入到命令中的任何内容都会随之记录。设置文件、转录文本和 memory 文件都会记录工作。在其中的每一个文件中,命令中的任何内容都可能与工作一起被记录下来。

MemoryLake 是一个 memory 层,用于存放你希望助手拥有的项目上下文,例如服务使用哪个数据库、暂存环境在哪里以及团队运行哪些命令,可供你连接的助手(如 ChatGPT、Claude Code 和 Codex)使用。

你用自己的语言亲自编写条目。不会从你的 .claude 文件夹、设置文件、会话转录、自动 memory、代码库或任何供应商的存储中读取、写入或删除任何内容。Claude Code 的权限规则按 Anthropic 描述的方式工作,你仍然需要按上述方法清理设置文件。

第 1 步:创建 API 密钥

登录并在仪表板中生成密钥。像存储任何其他凭据一样将其存储在代码库之外。

MemoryLake 控制台显示 API 密钥屏幕,在此创建并复制新密钥以供智能体使用
MemoryLake 控制台显示 API 密钥屏幕,在此创建并复制新密钥以供智能体使用

第 2 步:上传你的第一批 memory

编写上下文,而不是凭据:脚本预期的环境变量名称、服务运行的主机、团队轮换密钥的步骤。每个条目一个事实,严禁包含密码或令牌。

MemoryLake 工作区已上传首批文档,列出了每个成为可搜索 memory 的文件
MemoryLake 工作区已上传首批文档,列出了每个成为可搜索 memory 的文件

第 3 步:连接你的 AI 和智能体

连接 Claude Code 和你使用的任何其他助手。它们可以利用相同的书面上下文,而密钥则保留在你的密钥管理器中。

MemoryLake 集成屏幕列出了可以连接到 memory 层的 AI 客户端和智能体框架
MemoryLake 集成屏幕列出了可以连接到 memory 层的 AI 客户端和智能体框架

这在实践中改变了什么

第一个区别是上下文和凭据之间有了清晰的界限。项目知识存在于你编写的条目中,而开启系统的数值则存在于专门为它们构建的地方。

第二个区别是减少了将会话中粘贴密钥的理由。当助手已经知道哪个变量持有连接字符串时,命令就可以直接引用该变量。

Claude Code 权限的最佳实践

在授权前阅读命令。 尤其是当它连接到数据库或服务器时。

授权模式,而非字面命令。 像 Bash(npm run *) 这样的规则不会携带你输入过一次的参数。

将密钥保留在变量中。 这样规则记录的就是变量名。

将文件添加到代码库自身的 .gitignore。 不要依赖只有你机器才有的全局排除。

定期审查允许列表。 /permissions 显示每条规则及其来源。

扫描智能体文件和历史记录。 设置、转录文本、交接笔记和 memory 文件都可能携带命令。

有疑虑即轮换。 历史记录和分支会保留你删除的内容。

结论

当你选择停止 Claude Code 询问 shell 命令的选项时,Claude Code 会将该命令作为允许规则保存在 .claude/settings.local.json 中。如果命令包含密码或令牌,规则也会包含它。Claude Code 在创建该文件时会将其添加到你的全局 git 排除项中,但这种保护不会随代码库移动。Apiiro 发现了 1,122 份包含真实密钥的该文件公共副本,并在其检查的所有智能体文件中发现了 2,539 个不同的密钥。

检查你的代码库和历史记录中是否存在该文件,轮换它曾经持有过的任何内容,取消追踪并将其添加到代码库的 .gitignore 中,并改变你授权命令的方式。然后,将智能体编写的每个文件(包括 memory 文件)都视为可能携带密钥的文件。

常见问题

Claude Code 中的 .claude/settings.local.json 是什么?

它是项目本地设置文件,用于你在单个项目中的个人覆盖。Claude Code 还会将你的长期权限授权作为允许规则写入其中。

为什么 settings.local.json 包含我的密码?

当你授权一条 shell 命令并选择停止询问时,Claude Code 会将该命令保存为一条规则。如果你在该命令中输入了密码或令牌,它就会作为规则的一部分被保存。

settings.local.json 不是被自动 gitignore 了吗?

Claude Code 第一次在尚未忽略该文件的代码库中写入文件时,会将其添加到你的全局 git 排除项中。这保护了你的机器,但保护不了其他克隆版本,也不适用于你手动创建的文件或已经提交的文件。

我删除了文件。我安全了吗?

不一定。Apiiro 在该文件的早期版本中发现了 734 个在当前副本中不存在的密钥。请轮换该文件曾经持有过的任何凭据。

Anthropic 修复这个问题了吗?

Apiiro 报告称 Claude Code 的负责人表示团队正在研究预防措施,包括密钥扫描和自动模式。请检查 Claude Code 变更日志以了解授权保存方式的任何变化。

密钥扫描器能捕获这些文件吗?

能捕获很多,但不是全部。Apiiro 报告称,在 1,122 个包含真实密钥的文件中,有 215 个既没有被 gitleaks 标记,也没有被 TruffleHog 标记,因为命令内部的密码不符合密钥格式。