AI 编程工具执行 cat .env 后将结果塞入 outbound prompt,.gitignore 和提交时扫描均无法阻止,明确指出两类常见防御的盲区。
你让 agent 帮忙 debug 一个正在报错的部署。它跑了一下 cat .env,读到了 DATABASE_URL 和 GITHUB_TOKEN,然后直接把这段输出塞进下一个请求发给模型 provider —— 没有 commit,没有 push,secret 就这样离开了你的机器。
本文指出 secret 在 AI coding agent 生命周期中的哪个环节泄漏、哪些防线真正有用(按实际测量数据)、以及一份一个下午就能搭起来的 checklist。
泄漏路径在 tool 的 output 里,不在 Git 里
Claude Code、Codex、Cursor、Aider 或 Cline 不仅仅是 autocomplete。正如原文作者所说,这些工具"can read files, inspect directory trees, execute terminal commands, and feed the results back into a model"——正是这个反馈循环创造了新的数据出口。
关键点:当 agent 把命令输出放进下一个请求时,secret 的值"are no longer only on your machine—they have become part of the outbound prompt"。作者直接点破大多数越南团队正在依赖的两层防御:".gitignore does not prevent this. Secret scanning at commit time does not prevent it either. The secret does not have to enter Git history to leave the workstation."
从这个角度重新审视现有防御:pre-commit hook、CI 里的 secret scanning、PR review,都位于 commit 这个时间点之后。Agent 泄漏发生在更早之前,在 dev 笔记本的 egress 层。
Prompt 不是安全边界
很多团队的第一反应是在 CLAUDE.md 或 system prompt 里加规则:"不要读取 .env 文件"。在你停在那里之前,有一项研究值得先读一读。
那篇 agent-security 架构分析文章引用了 Zhang 等人的研究,AgentWorm: Self-Propagating Attacks Across LLM Agent Ecosystems(arXiv:2603.15727),2026 年 3 月发表,2026 年 7 月修订。据原文描述,作者团队在一个未修改的 OpenClaw 版本上评估了一个自复制 worm,测试床包含五个 LLM backend(Minimax-M2.5、DeepSeek-V3.2、GLM-5、Kimi-K2.5、Nemotron-3-Super)、三种 infection vector、三种 payload 类型和 2250 次独立 trial。
报告的数据:综合攻击成功率 63%,其中 skill-supply-chain vector 约 82%,传播能维持到第五个 hop。成功条件相当严格——恶意配置必须经历 session 重启后仍然存活,payload 必须在下次启动时运行,然后 agent 还得自行感染 peer。
从那篇分析中得出的原则值得贴墙上:"The component responsible for reasoning should not be the only component responsible for authorization." Prompt 仍然由同一个正在被攻击的系统来解释,所以它不等同于一层独立的 enforcement。
Sandbox isolation:唯一把成功率打到 0 的控制措施
在上述研究中评估的所有控制措施里,文章记录 sandbox isolation 是唯一能把总体成功率拉到 0 的手段,通过阻止对 host 的修改成为持久化。同时,公开的 OpenClaw 配置调查显示,观察样本中没有任何一个 deployment 开启了这个控制。
还有一个对运维很重要的细节:研究描述了"asymptomatic carriers"现象——即使 local 的控制阻止了 payload 运行,agent 仍然保留并传播恶意 state。也就是说,"没看到异常命令运行"不等于"机器是干净的"。如果只按执行行为来告警,就会漏掉 persistence 这一层。
第二道关卡:在 request 离开机器之前在 local 跑 DLP proxy
Sandbox 负责 host 部分。 outgoing payload 则需要在正确的 egress 边界上再设一道关。原文中关于 agent 用 DLP 的文章描述了这种方法——通过 Anonmyz,一个开源的 local DLP proxy,运行在 AI client 和 model provider 之间,按作者描述的处理循环如下:
Intercept request đi ra ngay tại máy dev.
Scan JSON body theo các pattern secret được hỗ trợ.
Thay giá trị phát hiện được bằng placeholder ngẫu nhiên.
Lưu mapping placeholder → giá trị thật trong vault in-memory, phạm vi từng request.
Chỉ gửi request đã sanitize lên provider, và khôi phục placeholder ở local khi response về.
Xoá vault sau khi trao đổi kết thúc.
据原文,唯一的 placeholder 能保留 identity 和 context:模型能区分两个不同的值,但学不到任何一个具体是什么——这和把所有东西都替换成 [REDACTED] 完全不同。
最难的部分,正如任何写过 streaming proxy 的人都会预料到的,是 SSE:一个 secret 可能被切断在两个网络 chunk 之间,所以独立扫描每个 chunk 会漏掉。作者描述的解决方案是维持一个有限大小的 look-behind 窗口,延迟可能是一个 pattern 开头的那几个字节,在无法安全处理 response 时 fail closed。
一个下午搭起防线的 checklist
这是分析部分,不是来源的推荐——请把它当作技术优先级顺序来读:
Tách credential thật khỏi workspace agent làm việc. Dùng file .env chứa giá trị dev/dummy, còn credential production nằm ở secret manager và chỉ nạp vào tiến trình runtime.
Cho agent chạy trong sandbox/devcontainer, không chạy trực tiếp trên máy host. Đây là control có bằng chứng định lượng mạnh nhất trong dữ liệu ở trên.
Đặt một chốt kiểm soát ở biên egress, dù là proxy DLP local hay tối thiểu là log lại toàn bộ request đi ra để audit được sau sự cố.
Coi rule trong prompt là defense-in-depth, không phải enforcement. Giữ nó, nhưng đừng tính nó vào cột "đã kiểm soát".
Rotate ngay các key đã từng nằm trong workspace mà agent có quyền đọc, trước khi bạn dựng xong ba lớp trên.
Proxy 层拦不住的
原文值得信赖的地方在于作者自己限定了范围。据描述,这类工具无法防御:本地进程已被拿下、client 故意绕过 proxy、通过其他网络信道外泄、detector 认不出的 secret 格式、以及已经泄露的 credential。作者也明确说它不能替代 least-privilege credential、secret rotation、endpoint isolation 或完整的 agent sandbox。
换句话说:proxy 是一层可执行的边界,排在 checklist 的第三层,前面是 credential hygiene 和 sandbox。
本周要做的事
跑一次试试:在一个全是假值的 .env 文件的 repo 里开启 agent,让它 debug 一个配置错误,然后精确检查有哪些东西离开了你的机器。如果你回答不了"今天有哪些 request 离开了我的机器"这个问题,那么第一层要搭的是 egress logging,还轮不到新工具。