Claude Code、Cursor 等 AI 工具执行 `cat .env` 后可能将密钥带入出站 prompt,作者开源了一款本地代理 Anonmyz,在请求离开机器前扫描 .env 密钥并替换,从根本上堵住了数据泄漏路径。
AI 编程助手能做的事远不止自动补全。
Claude Code、Codex、Cursor、Aider 和 Cline 这些工具可以读取文件、检查目录结构、执行终端命令,并将结果反馈给模型。正是这种上下文能力让它们变得好用——但同时也创造了数据意外暴露的新路径。
想象一下,你让一个助手调试一个部署失败的问题。它执行了:
env | grep -i secret
输出中包含了这样的值:
DATABASE_URL=postgres://admin:EXAMPLE_PASSWORD@internal-db:5432/app
GITHUB_TOKEN=ghp_EXAMPLE_TOKEN_NOT_REAL
INTERNAL_API_KEY=sk-example-not-a-real-key
这个助手可能会把命令输出包含在下次模型请求中。到了那个时刻,这些值就不再只存在于你的机器上——它们已经成为了出站提示词的一部分。
.gitignore 无法阻止这种情况。提交时的密钥扫描也无法阻止。密钥甚至不需要进入 Git 历史,就可能从你的工作站泄露出去。
我想要的是一个真正在边界层面的控制:在编程助手流量离开机器之前,立刻拦截。
所以我构建了 Anonmyz,一个面向 AI 编程助手的开源、本地 DLP 代理。
Anonmyz 运行在开发者机器上,位于 AI 客户端和模型提供商之间。
对于每个支持的请求,它会:
在本地拦截出站请求。
扫描其 JSON body 中支持的密钥和敏感数据模式。
用加密随机的占位符替换检测到的值。
在请求作用域的内存金库中存储占位符到值的映射。
只将脱敏后的请求发送给配置的模型提供商。
在标准响应或流式响应返回时,在本地恢复占位符。
在交换完成后清除请求作用域的金库。
模型仍然可以推理提示词的结构,但不需要看到原始凭证。
考虑一个包含以下文本的出站请求:
{ "input": "Debug this config: GITHUB_TOKEN=ghp_EXAMPLE_TOKEN_NOT_REAL" }
经过本地掩码处理后,提供商收到的内容概念上类似于:
{ "input": "Debug this config: GITHUB_TOKEN=[[GITHUB_TOKEN_7F3A9C2D]]" }
原始值保留在本地请求金库中。如果模型在其响应中包含占位符,Anonmyz 会在将响应返回给编程助手之前在本地替换它。
这与永久地将所有发现替换为 [REDACTED] 不同。唯一的占位符保留了身份和上下文:模型可以区分两个不同的值而无需知道任何一个值,并且本地工作流可以在返回路径上保持连贯。
大多数编程助手使用 Server-Sent Events 来流式传输模型输出。一个占位符——或者上游不安全响应中的原始密钥——可能被分割到任意的网络块中。
一个简单地独立扫描每个块的实现可能会漏掉这种情况:
chunk 1: sk-example-part-
chunk 2: two-not-a-real-key
每个块本身都不一定匹配一个完整的凭证模式。
因此,Anonmyz 在处理流时保持一个有界的向后查看窗口。它延迟发送可能是支持的密钥或占位符开头的字节,扫描组合边界,并在响应无法安全处理时失败关闭。
这种块边界行为通过分割位置测试来覆盖,而不是假设一次网络读取等于一个逻辑 token 或 SSE 事件。
在将提示词发送给云端模型之前,先发送给云端 DLP 服务,会产生另一个接收敏感提示词的第三方。
Anonmyz 将检测和可逆映射保留在工作站内。云提供商收到脱敏后的请求;反向映射所需的密钥在该交换期间保留在本地和内存中。
当前实现提供:
面向可配置 AI 客户端的环回反向代理模式
仅限于允许列表中 AI 域名的可选透明 MITM 模式
标准响应和 SSE 流式传输支持
请求作用域的内存金库
提供商适配器和允许列表请求头转发
本地仅元数据审计和指标端点
Codex Safe Session 启动器
VS Code 集成和 beta 版 JetBrains 集成
核心使用 Go 标准库编写,构建为单个二进制文件。代理不需要 Python 或 Node.js 运行时,Docker 是可选的而非强制的。
Anonmyz 设计用于检测支持的模式,例如:
API 密钥和提供商令牌
SSH 私钥块
内联密码和凭证
敏感的本地文件路径
其他配置的组织特定模式
模式匹配只是其中一层。在有用的地方,语义验证器会减少明显的误报——例如,通过检查候选值是否具有预期的结构,而不是将每个看起来随机的字符串都当作凭证处理。
没有任何检测器能识别所有可能的密钥格式。未知的专有格式需要自定义模式,而低熵值(如普通字典密码)在没有上下文的情况下本质上难以识别。
Anonmyz 旨在减少通过实际经过代理的 AI 流量对支持的密钥进行意外泄露。
它不能防御:
恶意或已被入侵的本地进程
绕过配置代理的客户端
通过无关网络通道进行的数据外泄
检测器无法识别的密钥格式
在启用 Anonmyz 之前已经暴露的凭证
它也不是最小权限凭证、密钥轮换、端点隔离或完整代理沙箱的替代品。
代理是分层安全模型中的一个可执行边界——不是解决所有代理安全问题的灵丹妙药。
安全工具比普通开发者工具值得更严格的审查。护栏中的 bug 可能造成虚假的安全感。
在静态安全审查期间,在当前发布路径之前发现并修复了几个边界问题:
IDE 集成不再自动执行在不受信任的工作区中找到的二进制文件。
Codex Safe Session 路由和传输设置不能被转发的参数覆盖。
远程明文 HTTP 上游被拒绝。
流式处理在块边界之间保留凭证向后查看。
标准上游响应有明确的大小限制。
新生成的 CA 密钥使用带 210,000 次迭代的盐化 PBKDF2-HMAC-SHA-256。
该项目还维护公开的威胁模型,并将绕过报告视为安全问题而非普通的功能请求。
这并不意味着该项目"已被证明安全"。这意味着它的声明是经过刻意限定范围的,其边界是旨在可测试的。
对于这样的项目,最有用的反馈不是"干得好"。而是一个可复现的绕过。
如果你使用 AI 编程助手,你可以通过以下方式提供帮助:
使用伪造的测试凭证运行 Anonmyz。
检查实际发送给上游提供商的内容。
尝试不寻常的 JSON 嵌套、工具结果负载和流式边界。
报告误报或不支持的密钥格式。
使用尚未覆盖的客户端或提供商适配器进行测试。
仓库、设置说明、威胁模型和安全策略可在此处获取:
如果该项目解决了你的问题,一个 GitHub star 可以帮助其他开发者发现它。如果它在你的环境中失败,一个包含最小复现步骤的 issue 更有价值。
AI 编程工具不应该仅仅因为能看到本地上下文就被禁用。我们应该能够在该上下文和云端之间放置一个可衡量的、本地的安全边界。