一句话版本
AI Agent 会把它"看到"的东西放进上下文窗口:读过的文件、命令的输出、环境变量。只要 API 密钥、数据库密码在这些地方出现过一次,它就可能被模型复述出来、写进日志、发送给模型服务商、或者被注入攻击外泄。 原则是:凭证不应该出现在模型能看到的任何地方。让系统代为使用凭证,而不是把凭证交给模型。
全文分三层:
- 通俗理解:别把密码写在会被复印的纸上
- 实际用处:常见的泄露路径
- 原理与工程要点:凭证代理、脱敏、日志卫生、泄露后的处理
第一层:通俗理解
1.1 别把密码写在会被复印的纸上
想象 Agent 的上下文窗口是一张会被反复复印、到处传阅的工作单:
- 发给模型服务商处理(一份副本);
- 记进对话历史和日志(又一份);
- 可能被总结、引用、显示在界面上(又一份);
- 如果被注入,还可能被发给攻击者(最糟的一份)。
你绝不会把保险柜密码写在这样一张纸上。但只要 Agent 执行了一次 cat .env 或 printenv,密码就已经写上去了。
第二层:实际用处
| 泄露路径 | 怎么发生 |
|---|---|
| 读配置文件 | Agent 为了理解项目,读了 .env、config.yaml、~/.aws/credentials |
| 命令输出 | 运行 printenv、env、调试脚本把环境变量打印出来;报错信息里带着连接字符串 |
| 工具返回结果 | 某个 API 的响应里包含了令牌 |
| 写进代码 | Agent 为了让测试通过,把密钥硬编码进源文件,然后提交了(见《秘密扫描》) |
| 日志和遥测 | 对话记录、调试日志、错误上报里包含了上下文 |
| 被注入后外泄 | 攻击者让 Agent 把环境变量发到外部(见《Markdown图片数据外泄》) |
社区里时常有人报告 AI 编程工具在聊天中原样显示了用户的 API 密钥,或者把密钥写进了提交历史。这通常不是"恶意",只是 Agent 在做它认为有帮助的事。
第三层:原理与工程要点
3.1 最好的办法:凭证代理
- Agent 的环境里只有一个代理地址,没有真正的密钥;
- 代理按目标地址决定附加哪个凭证,而且只对白名单地址附加;
- 即使 Agent 被完全控制,它也拿不到密钥本身,只能在白名单范围内使用它;
- 代理还能记录每次使用,限制频率(见《网络出口控制》)。
3.2 如果必须把凭证放进环境
| 措施 | 说明 |
|---|---|
| 短期、窄范围 | 几小时后失效;只能访问必需的资源(见《Agent权限设计》) |
| 文件不可读 | 敏感文件(.env、云凭证、SSH 私钥)在沙箱里不可见,或者明确禁止 Agent 读取 |
| 命令过滤 | 对 printenv、cat .env 一类命令要求确认 |
| 输出脱敏 | 命令输出进入上下文之前,用正则匹配已知的密钥格式(sk-...、AKIA...、ghp_...、私钥头等)并替换为 [REDACTED] |
| 专用测试凭证 | 给 Agent 用的是测试环境、沙箱账号的凭证,泄露了也没有实际损失 |
3.3 日志卫生
- 记录工具调用时,对参数和结果做同样的脱敏;
- 日志的访问权限要比普通日志更严格,保留时间更短;
- 错误上报服务(如崩溃收集)要配置过滤规则,不要上传完整上下文。
3.4 提交前拦截
Agent 能写代码、能提交,就要在提交前加一道 秘密扫描(见《秘密扫描》):
- 本地提交前钩子;
- 代码托管平台的推送保护;
- CI 里的扫描作为最后一道。
3.5 泄露之后
一旦发现密钥出现在对话、日志或提交里:
- 立即轮换(作废旧密钥、生成新密钥),这是唯一可靠的补救;删除日志或提交记录都不够,副本可能已经在别处;
- 检查这把密钥在泄露窗口内的使用记录;
- 找出泄露路径,补上对应的防护。
总结
| 层次 | 要点 |
|---|---|
| 直觉 | 上下文窗口是一张会被反复复印的工作单 |
| 路径 | 读配置、命令输出、工具结果、写进代码、日志、被注入外泄 |
| 最佳做法 | 凭证代理:Agent 只能使用,拿不到密钥本身 |
| 补救 | 泄露后立即轮换;删除记录不够 |