AI 博客

WAF 拦下了载荷,然后把它写进了你的智能体会读的地方

2026 年 8 月 9 日在 DEF CON 上发布的 GhostJacking,在厂商自家推荐的配置下对一台编码智能体报出了 90% 的成功率——因为逐字记录敌对输入本来就是防火墙的职责,而读这份记录的分诊智能体,手里握着操作者的凭据。没有漏洞利用、没有告警,每一个动作都是获授权的。解法是结构性的:把「读的智能体」和「动手的智能体」拆开。

作者 智能体 AI 维基 24 分钟读完

Web 应用防火墙挣的这份钱,靠的就是把它拦下的那个请求原样记下来——于是拦截日志成了贵司唯一一份任何匿名陌生人都能随意写入的语料,而它抵达分诊智能体时,还贴着「安全」标签。2026 年 8 月 9 日,Tenet Security 在 DEF CON 上以 GhostJacking 之名演示了这条路径,并报告在厂商自家推荐的配置下,对一台编码智能体十次里成了九次。没有任何东西被漏洞利用,没有任何告警响起,而智能体做出的每一个动作,都是它本来就有权做的。

被演示出来的是什么

这套手法就是间接提示词注入,只是配了一条可靠得反常的投递通道。攻击者发出一个他预期会被拦下的请求。安全平台尽了职:它拦住了这个请求,并把载荷逐字存了下来——因为一份会把证据清洗掉的日志,根本不算日志。此后——可能是几分钟,也可能是几天——有人让一台智能体去审一下被拦截的流量,它读到了那条记录,并照着躺在里面的那条指令做了。那个「十次成九次」的数字,是在 Cloudflare 自家推荐的配置下、针对 Claude Code 测出来的;Tenet 还报告了同一套模式在接入 Cloudflare、Datadog 与 Sentry 的智能体上都成立,并估计仅仅通过有问题的 Cloudflare 配置,就可能有一万五千多家机构暴露在外。

阶段团队是怎么读它的它实际上是什么
请求在边缘被拦下 一项奏效了的控制 一次由陌生人发起的、对内部存储的写入
载荷被存进事件日志 为调查而留存的证据 贴着内部标签、由攻击者执笔的文本
让智能体去分诊这份日志 把值班的苦力活去掉了 把不可信输入递给了一个握着凭据的进程
智能体照着它读到的去做 一次由内部工具发起的、获授权的变更 攻击者的下一步,由你替他执行
How a blocked request reaches an agent's tools An attacker sends a request that the edge web application firewall blocks. The firewall writes the payload verbatim into the block log alongside error tracker and APM data. A triage agent reads that log while holding the operator's credentials plus shell, cloud API and package installation tools, and from there the demonstrated actions follow: a DNS change, a credential read and an outbound request. The attacker's text crosses the perimeter once as evidence and a second time as instruction. One payload, two crossings your perimeter Attacker unlimited attempts Edge / WAF request blocked Block log payload stored verbatim error tracker · APM · SIEM Triage agent "review blocked traffic" Operator's credentials shell · cloud API package installation DNS change Credential read Outbound request Every action inside policy, so nothing in the EDR, WAF or IAM stack has anything to fire on.
同一份载荷跨过你的边界两次:第一次作为证据,第二次作为指令。只有第一次跨越被记成了事件。

为什么日志是攻击者拿到过的最好的一条通道

经由被抓取的网页或被投毒的文档做注入,一直都要看运气:智能体得访问到那个页面,内容得挺过检索,而且每次尝试都只有一投。拦截日志把这三条性质全都反了过来——正是这处反转,让这件事值得写一篇文章,而不只是一条脚注。

  • 投递由防御本身来保证。你不需要智能体去访问任何地方,你只需要防火墙做它被配置去做的那件事——而它每次都会做。
  • 尝试次数无限,且不花钱。攻击者一天可以发一千个变体,每一个都会被存下来。「被拦截」没有限速,没有任何报错会告诉他失败了,而失败一次的代价是零。
  • 读的人本来就被引导着去照办。「去查一下这些被拦截的请求」是一个鼓励细读、并对发现采取行动的任务。载荷不必击败系统提示词,它只需要装进这份工作里。
  • 那个存储在结构上就是被信任的。没人会把 SIEM 归类成不可信内容,因为里面别的一切都是你自家系统写的。唯一由外人掌控的那个字段,恰好就是智能体来读的那个。

同一条性质也让错误追踪系统变得危险:想把一段话写进一家公司的异常日志,最快的办法就是给它发一个畸形请求。所有由外人填写的自由文本字段——User-Agent 字符串、DNS 查询名、上传文件名、工单正文、来自 fork 的提交信息——都是同一条通道,只是节奏慢一些。

这条链子不需要任何漏洞利用

Three controls and the stage each one removes Three columns. Splitting the reader from the actor removes the ability to act on an injected instruction, leaving an agent that can only write words; it does not stop the payload arriving. Egress default-deny removes exfiltration and second-stage payload fetches; it does not stop a local state change. Approving on the concrete diff rather than the stated intent removes the silent change; it costs an interruption and depends on the reviewer reading the diff. Where the demonstrated chain breaks Reader / actor split Telemetry is read by an agent with read-only credentials and no state-changing tools. Removes: acting on the injected instruction at all. Does not stop delivery. Costs a second run and a human. Egress default-deny The agent process reaches an allowlist and nothing else; a new destination is an incident. Removes: exfiltration and second-stage payload fetches. Does not stop a local change. Costs allowlist maintenance. Approve on the diff The prompt shows the concrete effect — this DNS record, this policy, this command. Removes: the silent state change nobody reviewed. Fails if intent is shown instead. Costs an interruption per action.
三项控制,三个不同阶段。它们都不是检测器,而其中任意一项都能把已公开的那次演示打断。

读一遍已报告的这条链子——初始访问、提权、外传、持久化——最扎眼的地方是每一步都平平无奇。智能体跑的是它被允许跑的 shell 命令,调的是它被配置去调的云与 DNS API,装的是它天天都在装的包。已公开的一个例子里,智能体照着一条它误读成指令的日志记录,提出了 DNS 变更。因为每一个动作都在策略之内,EDR、WAF 与 IAM 这一整套里没有任何东西有得可报:这些控制不是被绕过了,是被满足了。

这与 2026 年其他值得研究的智能体事件形状相同。在Aurora 那批入侵里,是一个人拿着被盗凭据驱动一个商业编码智能体,没有任何新能力。在 ExploitGym 事件里,真正断掉的每一环都是基础设施。而在这里,攻击者一开始连凭据都不需要:他需要的是防御去把他记下来,以及智能体去读那份被记下来的东西。

Tenet 还披露了 Anthropic 的 Claude Desktop 上一个在演讲前已被修复的沙箱逃逸:出网网关接受了一枚由被分析文档自身提供的令牌。这一点值得记下,因为它道出了这一类问题的性质:「沙箱有网络控制」是一句该去测的主张,不是一条可以假定的性质——而这个测试很便宜。

这里没有一个平台打得了补丁的 bug

Six controls against three stages of the attack A matrix with six controls as rows and three stages as columns: stops delivery, stops the action, stops exfiltration. An injection classifier over the log stream and a system-prompt instruction to ignore instructions in data are partial on the action and no on the other two. Output filtering is no on delivery and the action and partial on exfiltration. Egress default-deny is no on delivery, partial on the action and strong on exfiltration. Splitting the reader from the actor is no on delivery and strong on both the action and exfiltration. Blocking credential reads below the model is no on delivery, strong on the action and partial on exfiltration. Nothing stops delivery, because recording the payload is the platform's function. What each control actually removes Stops delivery Stops the action Stops exfiltration Injection classifier on the log stream No Partial No "Ignore instructions in tool output" No Partial No Filtering the agent's answer No No Partial Egress default-deny No Partial Strong Reader / actor split No Strong Strong Credential reads blocked below the model No Strong Partial Nothing stops delivery: storing the payload verbatim is the platform's function, not its defect. Strong = removes the stage. Partial = raises the cost. No = leaves it intact.
真正管用的控制都坐在「读」与「做」之间的那条边界上。那些去读文本再做判断的控制,挪不动指针。

Cloudflare、Datadog 与 Sentry 在自己这一侧修不了这件事,除非把产品本身弄坏。忠实地记录敌对输入就是它们的功能;一个把载荷从自己的拦截记录里抹掉的 WAF,对那条记录本该支撑的调查毫无用处。不存在一个既保住证据又拿掉武器的补丁——所以真正有意思的问题不是厂商会发布什么,而是你的智能体站在「读」与「做」这条线的哪一侧。

有三种应对方案反复被提出,而它们没有一个撑得过基础率:

  • 在日志流上跑注入分类器。一个中等规模的站点每天拦下数以百万计的请求,而这份语料在构造上就是对抗性的——这是唯一一个攻击者能无限次尝试、失败没有任何反馈、每次尝试还不花钱的地方。任何阈值不是噪声就是筛子。
  • 「忽略工具输出里出现的指令。」那是一个有失败率的、被训练出来的偏好,不是一次有返回值的权限检查——而且真正得手的载荷并不与任务冲突,它们是任务的延伸。
  • 过滤智能体的回答。造成损害的是一次工具调用,它发生在任何回答存在之前的好几步。输出过滤管的是那份报告,不是那次运行。

真正能拦住它的是什么

Tenet 随演讲一起发布了一个开源加固工具 agent-jackstop:它默认拒绝出网、在命令执行前要求人工批准、告诉智能体把工具输出当作不可信、并在子进程层面拦住读凭据的动作。无论你是否采用它,这份清单的形状是对的——每一项都是在模型之下被强制执行的,而不是向模型提出请求。

  • 把读的人和动手的人拆开。回报最高、也最经得起「下一个换了名字的手法」的一处改动。读遥测的那台智能体只拿只读凭据、不配任何改变状态的工具;它产出的是一份书面结论。对结论采取行动是另一次运行,其输入是那份结论、而不是那条日志。
  • 智能体进程出网默认拒绝。把这份工作需要的目的地放进白名单,并把「第一次见到的目的地」当作事故。外传与第二阶段拉取都死在这里。
  • 批准要针对变更本身,而不是意图。凡是必须留在回路里的改变状态的工具,都要展示具体效果——这一条 DNS 记录、这一份 IAM 策略、这一行命令。一段关于意图的摘要,是由正被攻击者操纵的那次运行写出来的。
  • 在模型之下拒绝读凭据。环境变量导出、~/.aws、kubeconfig、云元数据端点。这里根本不涉及提示词,所以也没有提示词可被击败。
  • 把来源一路带到动作上。给每条取回来的记录打上信任档位,并把标记传播到这次运行的每一次工具调用。该告警的是「来源链里含有不可信字段」的那个动作——而不是那个字段的文本。

这一周唯一值得跑的那个测试

给自己发一个必定会被 WAF 拦下的请求,载荷里带一条无害指令:写一个特定的无害标记文件,或者请求一个别处都不会调用的特定内部 URL。然后看那个标记有没有出现。它只要一个下午,而且它把问题落在了你的技术栈上,而不是研究者的技术栈上。

否定结果是「你的遥测路径不是被演示出来的那一条」的唯一证据。肯定结果则直接给你一场本来需要你凭原则去争取的预算对话——外加一个可以进入「为分诊智能体变更把关」的用例集的测试用例。每月重跑一次,并在每次改动提示词或工具集之后再跑一次,因为暴露面是配置的性质,而配置会漂移。

常见问题

GhostJacking 是什么?

这是 Tenet Security 于 2026 年 8 月 9 日在 DEF CON 上披露的一种攻击手法:攻击者把指令种进 AI 智能体很可能会读到的运维数据里——被拦截请求的日志、错误报告、监控告警——好让智能体在一次寻常的分诊任务中把它们执行掉。它是经由安全遥测投递的间接提示词注入。

这是 Cloudflare、Datadog 或 Sentry 的漏洞吗?

不是。这些平台做的正是它们被造出来要做的事:逐字记录敌对输入,好让人去调查它。真正制造出暴露面的,是把一台带着凭据与工具的智能体指向那份记录。Tenet 那个「一万五千多家机构可能暴露」的估计,说的是配置,而不是某个产品缺陷。

上沙箱能解决吗?

只解决一部分,而且要看它的网络控制是否真的成立。Tenet 披露过一个此后已修复的桌面端智能体逃逸:出网网关接受了一枚由被分析文档自身提供的令牌。沙箱能把损害框住;它拦不住一台智能体用真实凭据去做一件获授权的事。

我们只让智能体读,这样安全了吗?

安全得多,但不是安全。一台只读的智能体仍可能被操纵着把它读到的东西说出去——写进一张工单、发进一个聊天频道,或塞进它去请求的一个 URL。把只读凭据与默认拒绝的出网配在一起,剩下的路径就很窄了。

怎么知道我们是不是已经中过招?

去看动作,别去看文本:一次丢下自己任务的分诊运行、一次对凭据文件的读取、一次联络从未联络过的主机。内容层面的检测在这里说明不了什么,因为那份载荷与「这份日志本就是为记录它而存在」的流量根本无从分辨。

延伸阅读

本站相关:

资料来源: