# 一份伪造的 bug 报告劫持了编码 agent

安全研究人员展示了一种名为「Agentjacking」的新攻击：往一家公司的 Sentry 里发送一份伪造的错误，它的 AI 编码 agent 就会读取那些「修复步骤」并执行——把你的凭证以你自己的权限交给攻击者。在测试中，Claude Code、Cursor 和 Codex 全都中招。这个教训比单个工具更大：你的 agent 读到的每一样不可信的东西，都是有人可以注入命令的地方。

- **Author:** Fedor Chishchin
- **Published:** 2026-06-23
- **Tags:** security, agents
- **Source:** https://fedorthinks.com/zh/blog/a-fake-bug-report-hijacked-the-agent

---

这是一个应该改变你对 agent 看法的攻击。Tenet Security 的研究人员披露了 **「Agentjacking」**——
[The Hacker News 在本月做了报道](https://thehackernews.com/2026/06/agentjacking-attack-tricks-ai-coding.html)。
手法简单得几乎离谱：攻击者只用一个很容易找到的公钥，就往一家公司的 Sentry（错误跟踪工具）里发送一份
**伪造的错误报告**。这份伪造的错误里包含「解决步骤」。当团队的 AI 编码 agent 读取这个错误来帮忙修复时，
它就会执行这些步骤——而这些其实是攻击者的命令——在开发者的机器上，以开发者自己的权限运行。

在测试中，[Claude Code、Cursor 和 Codex 全都这么干了](https://tenetsecurity.ai/blog/agentjacking-coding-agents-with-fake-sentry-errors/)。
它们分不清真错误和被植入的错误。攻击者的战利品：环境变量、AWS 密钥、npm token、git 凭证、私有仓库 URL。
Tenet 发现了 **2,388 家组织** 拥有暴露的、可被注入的密钥。

## 你的护栏没拦住它

可怕的地方在于什么 _没有_ 阻止它。根据这项研究，EDR、WAF、IAM、VPN、Cloudflare——甚至是 system prompt
里明确告诉 agent 不要信任外部数据的指令——全都没能拦住它。而 Sentry，在被要求从平台层面修复时，
[把这个问题称为](https://www.mallory.ai/stories/019ebbf0-cfe8-748c-bb06-d3a80fc817e5) **「技术上无法防御」。**

> 告诉模型「不要信任外部数据」不是一种安全控制。它只是一条建议，模型可以随意无视。

这就是这次攻击揭示的那个让人不舒服的真相：你没法靠 prompt 走到安全。如果 agent 既能读取攻击者控制的文本
_又_ 能执行命令，那么夹在中间的 prompt 指令就不是一堵墙。

## 真正的教训：每一个输入都是注入面

人们很想把这件事归到「Sentry 的一个 bug」名下。它不是。错误跟踪器只是那扇门。这个模式是普遍的：
**任何你的 agent 读取、又能被外人影响的东西，都是注入命令的地方**——错误日志、支持工单、issue 评论、
它浏览的网页、另一个工具的输出、一个 MCP server 的描述。我从其他角度写过这个——
[网页可以给你的 agent 下命令](/zh/blog/the-webpage-can-give-your-agent-orders)——而 Agentjacking
就是同一个教训换了一扇新门。

## 真正能保护你的是什么

这不是靠更好的 prompt 修好的。这是靠架构修好的：

- **把读和做分开。** 吞下不可信文本的那部分 agent，不应该是能执行命令的那部分。在它们之间设一道真正的边界。
- **把执行放进沙箱。** 在一个隔离的环境里运行 agent 的命令，不让它接触真实的凭证、云密钥或你仓库的密钥。
  就算被劫持了，它也什么都拿不到。
- **始终最小权限。** agent 只应该够得到任务需要的东西。这次攻击里大部分战利品，都是 agent 根本没必要看到的凭证。
- **任何要执行或要发送的东西，都要人来批准。** 读取很便宜；执行和外泄才是你设关卡的地方。

## 结论

Agentjacking 其实跟 Sentry 没什么关系。它干净利落地证明了一件事：一个既读取不可信文本又执行命令的 agent，
离替攻击者干活只差一条精心构造的消息。

**把你的 agent 读到的每一个输入都当成敌对的，把「读取」和「执行」分开，并对它运行的东西做沙箱——
因为你没法靠 prompt 逃出注入。** 那扇门会不断变化。解决办法是你放在它后面的那道边界。
