如何用一条命令阻止 Claude Code、Codex CLI、Cursor 和 OpenCode 读取你的 .env
要阻止 AI 编程智能体读取你的 .env 文件,就在智能体和你的文件之间放一层防护:拒绝这些读取,并把智能体工具返回内容中的密钥去掉。zn-gate 用一条命令 npx -y zn-gate init 就能为 Claude Code、Codex CLI、Cursor 和 OpenCode 做到这一点,再用第二条命令 npx -y zn-gate check 确认它确实生效。它是开源的(MIT),在你的机器上运行,不需要账号,默认不会向任何地方发送任何内容。
本指南说明这条命令在每个智能体里改了什么、如何验证、它不覆盖什么,以及如何移除。
为什么编程智能体读取 .env 会有问题?
编程智能体通过调用工具来工作:读文件、搜索仓库、运行 shell 命令。工具返回的所有内容都会加入对话,而对话会被发送给模型提供商。问题出在智能体打开的文件恰好是 .env 的时候。
举一个具体的例子。你问智能体为什么数据库迁移失败。它决定检查配置,于是读取了 .env。文件里有 DATABASE_URL=postgres://app:password@db:5432/main、一个支付密钥和其他一些值。这些行现在成了上下文的一部分:它们可能被发送给提供商,保存在智能体磁盘上的会话日志里,也可能出现在之后的回答中,或出现在智能体写的某条命令里。你从未在聊天中输入过这个密码,它却还是进去了。
这不需要攻击者:一个乐于助人的智能体会去读那个能解释问题的文件。它从网页或工单里读到的文字,也可能把它引向本来没有理由打开的文件。在提示词里要求智能体不要读取密钥,只是一个请求,不是一种控制。在工具执行之前运行的检查才是控制,而这正是 zn-gate 增加的东西。
开始之前你需要什么?
你需要 Node.js 18 或更高版本。打开终端并运行:
node --version
如果提示找不到命令,或显示的版本低于 18,请从 nodejs.org 安装 LTS 版本,并打开一个新的终端。Claude Code 插件的要求更高一些:Node.js 20.12 或更高版本、Git,以及 Claude Code 2.1.295 或更高版本。当前的 Node.js LTS 版本同时满足这两项要求。
请在你自己的终端里输入命令(macOS 用 Terminal,Windows 用 PowerShell 或命令提示符),不要在编程智能体的聊天窗口里输入。init 会让你确认每一步;当由 AI 智能体或脚本运行它时,它只会打印这些步骤,而不会执行。
如何用一条命令保护机器上的所有智能体?
npx -y zn-gate init
init 会查找 Claude Code、Codex CLI、Cursor 和 OpenCode。对每个尚未受保护的智能体,它会显示将要执行的配置,在你确认后执行每一步,最后进行一次检查。未安装的智能体会被跳过。
在 Windows 上,PowerShell 有时会提示 "running scripts is disabled on this system"。请用 npx.cmd 代替 npx(其他命令用 npm.cmd、zn.cmd),或者在命令提示符里运行同样的命令。
init 在每个智能体里安装了什么?
每个智能体允许外部工具接入的方式不同,所以 init 为每个智能体使用不同的机制:
| 智能体 | 安装的内容 | 机制 | 之后你要做的 |
|---|---|---|---|
| Claude Code | 来自 usezn/zn marketplace 的 zn-gate 插件 |
Hooks,由插件提供 | 开启一个新的 Claude Code 会话 |
| Codex CLI | zn 的 hooks,通过 npm install -g zn-gate 和 zn hooks install codex 安装 |
Hooks(hooks.json) |
打开 Codex,用 /hooks 批准新的 hooks |
| Cursor | zn 的 hooks,通过 zn hooks install cursor 安装 |
Hooks(hooks.json) |
重启 Cursor |
| OpenCode | zn 的插件,通过 zn hooks install opencode 安装 |
插件文件(plugins/zn-gate.js) |
重启 OpenCode |
如果你想一个一个智能体地来,这些就是 init 执行的相同步骤。对 Claude Code:
claude plugin marketplace add usezn/zn
claude plugin install zn-gate@usezn
对另外三个:
npm install -g zn-gate
zn hooks install codex
按需把 codex 换成 cursor 或 opencode。这些命令写入你的用户配置。加上 --project 则写入当前项目(见“可能出什么问题,如何修复?”一节)。
智能体受到保护之后有什么变化?
插件或 hooks 生效后:
- 智能体无法读取含有真实值的
.env文件,也无法读取凭据文件,例如~/.aws和~/.ssh下的文件。 - 工具返回内容中的密钥,会在模型看到之前被替换为标记或被遮盖。
- 你粘贴到提示词里的密钥,会在发送之前被拦截。
- 智能体不能写入 zn 自己的文件夹(
~/.zn),也不能修改保护它的 hook 和插件配置。在 Cursor 中,后一点只是尽力而为。
这些保护能做到什么程度,取决于每个智能体的 hooks 允许什么,而且差别很重要:
| 清理工具输出 | 阻止读取 .env |
阻止粘贴的密钥 | |
|---|---|---|---|
| Claude Code | 所有工具,包括 shell、文件读取、搜索和 MCP | 是 | 是 |
| Codex CLI | 是,但结果会被替换成清理后的文本,而 Codex 自己的会话日志保留原文 | 是 | 是 |
| Cursor | 仅限 MCP 输出;shell 输出和文件内容不会被清理 | 是 | 是 |
| OpenCode | 所有工具 | 是 | 是 |
完整的兼容性表格(包括 hook 无法运行时会发生什么)见 compat.md。各智能体的安装指南从 安装 开始。
如何检查是否生效?
npx -y zn-gate check
check 会创建一个临时文件夹,里面有两个文件:一个带假密钥的 .env,和一个普通文本文件。对每个为你的用户配置好的智能体,它会像你的智能体一样,请 zn 的 hook 决定是否允许读取这两个文件。对于插件运行在 OpenCode 内部的 OpenCode,它改为检查 zn 的规则。只有 .env 文件被阻止、普通文件被放行时,才算该智能体受到保护。
不会通过网络发送任何内容,不会启动任何智能体,也不会更改任何设置。结束时文件夹会被删除。每个智能体会得到三种结果之一:
- OK:zn 正在保护它。引号中的文字是智能体尝试读取该文件时被告知的内容。
- -:zn 没有为它配置,或只为某个项目配置。该行会给出配置它的命令。未安装的智能体会显示为 "not found on this machine"。
- X ... NOT protected:zn 已配置,但无法保护该智能体。该行会说明原因以及该运行什么命令。
只有当所有为你的用户配置的智能体都受到保护时,check 才会以退出码 0 结束。每一行的含义见 检查是否生效。
你自己的应用怎样继续获得 .env 里的值?
智能体无法再读取 .env 之后,你的应用仍然需要这些值。zn-gate 可以把它们保存在你机器上的加密保险库中,并在文件里留下标记:
npx -y zn-gate unlock
npx -y zn-gate env shadow .env
第一次 unlock 会创建保险库。执行 env shadow 之后,文件里是 __ZN_STRIPE_KEY__ 这样的标记,而不是真实的值,命令也会告诉你如何撤销这一改动。要用真实的值启动你的应用,先允许该程序一次,再通过 zn-gate 运行它。如果你用 npm run dev 启动应用:
npx -y zn-gate secret allow STRIPE_KEY --command npm
npx -y zn-gate run --secrets STRIPE_KEY -- npm run dev
--secrets STRIPE_KEY 会把真实的值放进应用的环境变量。大多数 .env 加载器(包括 dotenv)不会覆盖已经设置的变量,所以应用拿到的是真实的值,而不是标记。zn 会在智能体之外的系统对话框里请你确认。在服务器上或通过 SSH 时没有对话框:请在单独的终端里运行 npx -y zn-gate unlock --foreground,并在那里回答。尽量只允许范围最窄的程序。npm、node、python 以及其他解释器会运行任何交给它们的代码,因此允许其中一个,就等于让它运行的每个脚本都能读到该值,zn 会在你这样做时发出警告。更多内容见保险库文档。
可能出什么问题,如何修复?
升级 Node.js 之后,智能体拦截了每一条提示词。 hook 指向的是你运行 init 时的那个 Node.js。如果你升级、移动或删除了它(比如用 nvm),hook 就无法启动。此时 Claude Code 2.1.295 或更高版本、Cursor 和 OpenCode 会拦截提示词,而不是不加检查地放行;Codex CLI 则会放行。运行 npx -y zn-gate check:它会指出每个未受保护的智能体以及修复它的命令,通常是 npm install -g zn-gate,再加 zn hooks install <agent>。
Claude Code 里同时装了插件和 hooks。 如果你在安装插件之前运行过 zn hooks install claude-code,请先运行 zn hooks uninstall claude-code,否则两套 hooks 都会运行。
Claude Code 的设置关闭了 hooks。 在由组织管理的电脑上,Claude Code 可能被设置为忽略你自己安装的 hooks(托管设置中的 disableAllHooks 或 allowManagedHooksOnly),而且不会提示你。你自己的设置里的 disableAllHooks 效果相同。check 会读取这些设置文件,并把该智能体报告为未受保护;它也能发现 zn-gate 插件被停用。npx -y zn-gate status 发现这样的设置时会打印一条提示。请让管理员把 zn 加入托管设置。通过 claude.ai、设备管理(MDM)或 Windows 注册表下发的策略不会被读取。
Codex 似乎没有反应。 新增或修改过的 hooks,只有在你于 /hooks 中批准之后才会运行。
你只为某个项目安装了。 使用 --project 的安装会在项目内写入 .claude/settings.json、.codex/hooks.json、.cursor/hooks.json 或 .opencode/plugins/zn-gate.js 这样的文件。check 会列出这种配置,但不会运行它。没有在 PATH 中安装 zn 的同事克隆该项目后,这些文件不会带来任何检查,所以请在每台运行智能体的机器上都安装 zn。
zn-gate 不覆盖什么?
- 它只是一层防护,不是保证。zn 不认识的格式的密钥,如果又不在保险库里,仍可能到达模型。
- 在 Cursor 中,shell 输出和文件内容不会被清理。由 shell 命令打印出来的密钥,或位于未被阻止的文件中的密钥,会到达模型。要降低这一风险,请对你的
.env文件执行env shadow,并把密钥放在保险库里。 - 在 Codex CLI 中,hooks 是一种护栏,而不是强制执行的边界,Codex 自己也是这样描述它的 hooks 的。Codex 在本地保存的会话日志里仍然有原始输出。
- 不覆盖:Cursor CLI(
cursor-agent)、Hermes Agent、Gemini CLI、Copilot CLI、云端的 Claude Code 会话、Cowork 和聊天对话。 - 保险库处于解锁状态时,以你的用户身份运行的任何程序都可以按名称向它索取已保存的密钥。不需要时请把它锁上。
- 在其他编辑器(VS Code、Antigravity、Windsurf、Cline、Zed、JetBrains、Continue)中,zn-gate 只作为 MCP 服务器工作,由智能体自行决定何时调用。在那里它无法阻止对你的
.env文件的读取。配置方法见编辑器。 - Python 包面向你自己构建的智能体,例如 LangChain、CrewAI、LlamaIndex 或直接调用工具。它不保护编程智能体。
什么会离开你的机器?
默认没有任何内容。工具输出和工具调用参数在任何配置下都不会被发送。只有当你同时设置 ZN_CLOUD=1 和 ZN_API_KEY,或在 Claude Code 插件中设置 API 密钥选项时,提示词才会发送到可选的云端检查。zn-gate 检测到的密钥会先在本地移除;这条路径不会移除个人数据。
要查看你自己的配置,运行:
npx -y zn-gate status
该命令会打印包和规则的版本、当前启用的检测引擎、可选的云端检查是否开启,以及是否设置了 API 密钥。使用统计分享默认关闭,并有单独的状态命令:zn-gate stats share status。完整表格见什么会离开你的机器。
如何移除它?
- Codex CLI、Cursor 或 OpenCode:
npx -y zn-gate hooks uninstall <agent>,例如npx -y zn-gate hooks uninstall codex。如果只为某个项目安装过,请加上--project。 - Claude Code:在 Claude Code 里打开
/plugin并移除 zn-gate,或用claude plugin disable zn-gate@usezn停用它。用claude plugin enable zn-gate@usezn重新启用。如果你为 Claude Code 安装的是 zn 的 hooks 而不是插件,请运行npx -y zn-gate hooks uninstall claude-code。 - 保险库:
env shadow会打印恢复原来.env的确切命令,即npx -y zn-gate env unshadow .env --backup <name>,其中<name>是它显示的备份名称。
常见问题
如何阻止 Claude Code 读取我的 .env 文件?
在你自己的终端里运行 npx -y zn-gate init。对 Claude Code,它会安装 zn-gate 插件,阻止读取含有真实值的 .env 文件和凭据文件。之后开启一个新的 Claude Code 会话,并运行 npx -y zn-gate check 来确认。
zn-gate 也适用于 Codex CLI、Cursor 和 OpenCode 吗?
适用。对这三个工具,init 会安装 zn 的 hooks(OpenCode 则是一个插件文件)。Codex 会要求你用 /hooks 批准新的 hooks。Cursor 只会清理 MCP 工具的输出,所以那里的 shell 输出和文件内容不会被清理。
需要账号、API 密钥或网络连接吗?
不需要账号,也不需要 API 密钥。安装时会从 npm 下载软件包,Claude Code 插件则从 GitHub 获取。此后,默认情况下没有任何内容离开你的机器:工具输出和工具调用参数在任何配置下都不会被发送。提示词的云端检查默认关闭,只有同时设置 ZN_CLOUD=1 和 ZN_API_KEY,或在 Claude Code 插件中设置 API 密钥选项,才会启用。
做完这些之后,我的应用还能读取 .env 里的值吗?
智能体无法读取含有真实值的 .env 文件,但你的应用仍然可以拿到这些值。运行 npx -y zn-gate env shadow .env,把值移入 zn-gate 本地的加密保险库,然后在允许相应程序之后,用 zn-gate 的 run 命令启动你的应用。
怎么知道保护真的生效了?
运行 npx -y zn-gate check。它会创建一个临时文件夹,里面有一个假的 .env 和一个普通文件,让已安装的 hook 去读取这两个文件,只有 .env 被阻止、普通文件被放行时,才会把该智能体判定为已受保护。
它不能防护什么?
它只是一层防护,不是保证。zn 不认识的格式的密钥,如果又不在保险库里,仍可能到达模型;在 Cursor 里,由 shell 命令打印出来的密钥也不会被清理。云端的 Claude Code 会话、Cowork 和聊天对话不在覆盖范围内。
如何卸载 zn-gate?
对 Codex CLI、Cursor 或 OpenCode,运行 npx -y zn-gate hooks uninstall 加上智能体名称,例如 codex。对 Claude Code,在 /plugin 中移除插件,或运行 claude plugin disable zn-gate@usezn。
想在你自己的智能体上试一试,运行 npx -y zn-gate init(MIT,本地运行,无需账号),然后运行 npx -y zn-gate check。代码在 GitHub 上,各智能体的指南从 安装 开始。