编程智能体会把你的 API 密钥留在对话记录里吗?
会。Claude Code、Codex CLI、Cursor 和 OpenCode 都会记录你的对话,经过工具调用的密钥,比如读取文件或打印环境变量的命令所带出的密钥,可能就留在这份记录里。Claude Code 的文档说得很直接:它的文件是明文,经过工具的所有内容都会写入磁盘上的对话记录。
本指南说明四个智能体各自把历史存在哪里、各厂商对保留和上传有哪些文档说明、zn-gate 对此做了什么和没做什么,最后给出一份清理清单。关于厂商的每一条说法都链接到该厂商自己的页面。文档里找不到的地方,我们会直接说明,不做猜测。
为什么密钥会出现在对话记录里?
智能体靠调用工具工作:读文件、运行命令、搜索文件夹、调用 MCP 服务器。每次调用的结果都会返回给模型,智能体还会保留一份对话日志,方便你之后恢复会话。如果结果里包含 AWS_ACCESS_KEY_ID=...,原因是智能体读了 .env 文件或运行了 env,那么这个密钥就同时存在于模型的上下文和日志中。
因此要考虑两份副本。一份在你的磁盘上,位于智能体的历史文件夹里。另一份在模型提供方处理并可能保留你请求的地方。清理第一份并不会影响第二份。
各个智能体把历史存在哪里?
| 智能体 | 本地存储(按文档) | 文档中的控制项 |
|---|---|---|
| Claude Code | ~/.claude/projects/<project>/<session>.jsonl,明文,较大的工具输出放在 tool-results/ 文件夹 |
cleanupPeriodDays,默认 30 天,最小 1, CLAUDE_CODE_SKIP_PROMPT_HISTORY, claude purge |
| Codex CLI | 位于 CODEX_HOME(默认 ~/.codex)下:配置、认证、日志和会话 |
history.persistence、history.max_bytes、codex exec --ephemeral |
| Cursor | 我们读过的页面没有说明 | Privacy Mode(服务器端) |
| OpenCode | ~/.local/share/opencode/,会话数据在 project/<project-slug>/storage/ |
我们读过的页面没有说明 |
Claude Code
Claude Code 的应用数据文档说,~/.claude 下的文件是明文,经过工具的所有内容都会写入磁盘上的对话记录:文件内容、命令输出和粘贴的文本。完整对话在 projects/<project>/<session>.jsonl 中,包含每条消息、每次工具调用和每个工具结果。子智能体的对话记录有单独的文件夹,较大的工具输出会被转存到会话旁边的 tool-results/ 文件夹。
文件超过 cleanupPeriodDays 后,Claude Code 会删除它们。默认值是 30 天,最小值是 1;文档说明设为 0 会触发校验错误。数据使用页面重复了本地缓存默认 30 天的说法,并指向同一页面来说明如何清除。它还指出,最近一次在 Claude Desktop 或 Cowork 中启动或继续的会话,其对话记录默认不受这个期限限制。
要缩短保留期,在 ~/.claude/settings.json 里设一个更小的值:
{
"cleanupPeriodDays": 1
}
同一页面(明文存储)列出了少留数据的方法。设置环境变量 CLAUDE_CODE_SKIP_PROMPT_HISTORY 后,任何模式下都不会写入对话记录和提示词历史。在非交互模式下,也可以在 -p 旁边传入 --no-session-persistence。claude purge 会在展示删除计划并请求确认后,删除 Claude Code 为某个项目保存的对话记录、记忆和提示词历史。这些文件本身也是普通文件,你也可以自己删除。
提示词历史是单独的文件。~/.claude/history.jsonl 保存你输入过的每条提示词,文档说明按时间清理不会移除这些条目,除非适用 HIPAA 配置。因此,粘贴进提示词的密钥在对话记录消失后仍可能留在那里。
Codex CLI
OpenAI 的环境变量页面说,CODEX_HOME 设置 Codex 状态的根目录,其中包括配置、认证、日志、会话、skills 和软件包元数据,默认值是 ~/.codex。配置参考中有两个历史相关设置:history.persistence("Control whether Codex saves session transcripts to history.jsonl",取值 save-all 或 none)和 history.max_bytes,后者通过丢弃最旧的条目来限制历史文件的大小。
# ~/.codex/config.toml
[history]
persistence = "none"
用于自动化时,命令参考列出了 codex exec --ephemeral:"Run without persisting session rollout files to disk"。
我们读过的页面里没有找到的内容:会话文件的保留期限,以及 sessions 下子文件夹的具体结构。需要这些细节的话,请直接查看你自己的 ~/.codex 文件夹。
Cursor
Cursor 的隐私帮助页面和数据使用概览描述了服务器端的情况,两者都没有说明聊天历史在你的电脑上存放在哪里,也没有说明如何删除。这是我们能核实的范围内的空白,并不表示没有存储任何内容。请在应用自己的设置里查看是否有历史记录控制项。
服务器端有文档说明。开启 Privacy Mode 时,Cursor 表示你的数据不会用于训练,并与其模型提供方签有零数据保留协议,但有一个例外:如果你的提示词或对话触发了滥用检测器,数据可能会被存储用于调查。关闭 Privacy Mode 时,概览说 Cursor 可能保留并使用代码库数据、提示词、编辑器操作和代码片段来改进其 AI 功能。即使你使用自己的 API 密钥(帮助页面说明此时零数据保留不适用:你的数据遵循你的提供方的隐私政策),请求也会经过 Cursor 的后端,Cursor 还会在其服务器上临时缓存文件内容以降低延迟。概览没有给出 Cursor 自身存储的保留期限。
OpenCode
OpenCode 的故障排查页面列出了位置。日志在 ~/.local/share/opencode/log/。会话数据在 ~/.local/share/opencode/ 下的 project/ 文件夹中:项目位于 Git 仓库内时在 <project-slug>/storage/,否则在 global/storage/。在 Windows 上,基础文件夹是 %USERPROFILE%\.local\share\opencode。
我们能打开的 OpenCode 当前文档没有描述会话共享,也没有相关设置。如果你共享过会话,请查看你所用版本自带的帮助,了解如何移除链接。
我们没有找到本地会话数据的保留期限说明。
智能体会上传对话记录吗?
对于模型调用,按设计就会:智能体把你的提示词和工具结果发送给模型提供方,模型也正是这样才看到密钥的。厂商之后保留什么,取决于产品和套餐。
对 Claude Code,数据使用页面说,发送的数据包括所有用户提示词和模型输出,传输过程加密。Anthropic 的保留期取决于账户类型:Free、Pro 和 Max 账户,如果你允许数据用于改进模型则为 5 年,不允许则为 30 天;Team、Enterprise 和 API 默认 30 天。零数据保留适用于 Claude for Enterprise 上的 Claude Code,按组织为符合条件的账户启用。
同一页面列出了对话记录会被主动发送的情况。运行 /feedback(以及 /bug 或 /share)会发送你的对话历史副本,这些报告会保留 5 年。如果你在会话调查之后,对可选的 "Can Anthropic look at your session transcript" 追问回答 Yes,对话记录就会被上传;已知格式的 API 密钥和令牌在上传前会被遮盖,其他内容则不会。你可以用 DISABLE_FEEDBACK_COMMAND=1 关闭反馈命令,用 CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY=1 关闭调查。
对 Codex CLI,我们读过的文档页面没有描述本地会话文件的上传,我们也不声称 OpenAI 在其服务器上保留什么。这取决于你的登录方式和套餐,请阅读 OpenAI 针对你账户的条款。Cursor 和 OpenCode 请见上文各节。
zn-gate 改变了什么,没有改变什么?
zn-gate 是位于智能体和它所用工具之间的本地层。工具返回输出时,zn-gate 会在模型看到结果之前,把其中的密钥,例如 AWS 密钥、GitHub 令牌、JWT、私钥和数据库 URL 中的密码,替换成 __ZN_AWS_KEY_1__ 这样的标记。由于对话记录保存的是展示给模型的内容,新的对话记录里存的是标记而不是真实值。粘贴到提示词里的密钥会被拦截,不会发送。
在 Claude Code、Codex CLI 和 OpenCode 中,zn-gate 会清理智能体自带工具的输出。在 Cursor 中,只清理 MCP 工具的输出。shell 输出和文件内容在那里无法改写,所以智能体读取的文件里的值,或命令打印出的值,仍可能到达模型。
需要记住的限制,来自 zn-gate 的威胁模型:
- 它不会清理你安装之前写下的对话记录,这些文件里原有的内容依然在。
- 它不控制智能体厂商在其服务器上保存什么。它减少发送出去的内容,但无法收回之前已经发送的内容。
- Codex 无法改写工具输出,所以 zn-gate 替换的是模型看到的结果。Codex 自己位于
~/.codex/sessions的会话日志会保留原始输出。 - 在 Claude Code 中,对话记录里保存的是清理后的工具输出,但被 zn-gate 拦截的提示词会以明文留在其中,Claude Code 自己的文档也是这么说的。zn-gate 为本地命令还原某个值时,确认对话框里显示的命令也会记录在那里。
- OpenCode 在命令仍在运行时写入实时输出,那时 zn-gate 还看不到,所以这部分会留在 OpenCode 的本地数据库里。
如果密钥可能已经在对话记录里,怎么办?
-
轮换密钥。 在服务商处创建新密钥并吊销旧密钥。删除文件无法撤销已发送给模型或已进入备份的副本,所以这一步排在最前面。
-
找到包含它的对话记录。 在历史文件夹里搜索密钥的前缀。例如在 macOS 或 Linux 上:
grep -rl "AKIA" ~/.claude ~/.codex ~/.local/share/opencode 2>/dev/null把
AKIA换成你要查找的密钥前缀。用前缀,不要用完整密钥,以免密钥进入你的 shell 历史。 -
删除不需要的内容。 从上面列出的文件夹中删除匹配的会话文件,或者在 Claude Code 里把
cleanupPeriodDays设为较小的值,在 Codex 里设置persistence = "none"。Cursor 请使用应用自带的历史记录控制项,因为我们没有找到文档化的路径。对于 Claude Code,claude purge还会删除该项目在history.jsonl中的记录行。 -
检查其他副本。 备份、主目录的云同步,以及你共享过的任何会话。如果你共享过 OpenCode 会话,请按你所用版本的帮助说明移除链接。在 Claude Code 中,
/feedback报告由 Anthropic 按上文所述保留。 -
阻止新的副本。 把值从智能体会读取的地方拿走,并在路径上放一个密钥清理层。
怎样避免新的密钥进入对话记录?
安装 zn-gate,把 .env 的值移入它的本地保险库。文件里只留标记,所以读取它不会看到任何值:
npx -y zn-gate init
npx -y zn-gate unlock
npx -y zn-gate env shadow .env
npx -y zn-gate check
init 在每次更改前都会询问,并为它找到的 Claude Code、Codex CLI、Cursor 和 OpenCode 完成设置。unlock 第一次运行时创建保险库。env shadow 把 .env 中的真实值替换成 __ZN_STRIPE_KEY__ 这样的标记,并保留一份加密副本,可用 zn env unshadow 恢复。check 用临时文件夹里的假密钥测试保护是否生效,并告诉你哪个智能体没有受到保护。设置的详细步骤见如何用一条命令阻止 Claude Code、Codex CLI、Cursor 和 OpenCode 读取你的 .env。
本指南没有涵盖什么?
- 各智能体的路径和设置会随版本变化。上文内容来自写作时厂商的文档,你所用版本里各文件夹的文件结构可能不同。
- 我们没有在每个平台上测试删除,也没有核实厂商如何处理其服务器上已删除的数据。
- 云端会话、聊天产品和其他编辑器不在范围内。zn-gate 不覆盖云端的 Claude Code 会话、Cowork 和聊天。
- 密钥清理只对它能识别的格式有效。格式未知的密钥可能漏过,这就是泄露之后第一步要轮换密钥的原因。
常见问题
编程智能体会把我的 API 密钥保存在对话历史里吗?
有可能。Claude Code 的文档说,经过工具的所有内容都会以明文写入磁盘上的对话记录,包括文件内容和命令输出。Codex CLI 的文档说明它把会话文件保存在 CODEX_HOME 下,OpenCode 的文档也给出了本地会话文件夹。我们读过的 Cursor 页面没有说明聊天历史在本地存放在哪里。
Claude Code 把对话记录存在哪里,保留多久?
存在 ~/.claude/projects/,每个会话一个 .jsonl 文件。Claude Code 会在超过 cleanupPeriodDays 天后删除它们,默认 30 天,最小值为 1。
怎样让 Codex CLI 不保存历史?
在 config.toml 的 [history] 表里把 persistence 设为 none,即可停止写入 history.jsonl;运行 codex exec 时加上 --ephemeral,非交互运行就不会写会话文件。文档没有给出交互式会话文件的保留期限。
zn-gate 会清理已经存在的对话记录吗?
不会。zn-gate 在模型看到之前,把工具输出里的密钥替换成标记,所以新的对话记录里保存的是标记而不是真实值。它不会改写你安装之前已经写入的文件,也不能控制智能体厂商在其服务器上保存什么。
如果密钥已经进入了对话记录,该怎么办?
先到服务商那里轮换密钥,因为删除文件无法撤销已发送给模型或已进入备份的副本。然后删除包含该密钥的对话记录,并用 npx -y zn-gate env shadow .env 把 .env 里的值移入保险库。
zn-gate 对 Cursor 的保护和其他智能体一样吗?
不完全一样。在 Cursor 里,zn-gate 只清理 MCP 工具的输出,shell 输出和文件内容在那里无法改写,所以请用 npx -y zn-gate env shadow .env 把值从文件里拿走。粘贴到提示词里的密钥在这四个智能体中都会被拦截。
想在你自己的智能体上试用,运行 npx -y zn-gate init(MIT 许可,本地运行,无需账户),然后运行 npx -y zn-gate check。代码在 GitHub,各个智能体的指南从安装开始。shell 命令可以通过哪些途径读到受保护文件,见编程智能体如何间接读取你的 .env 文件。