FlawOpen

flawopen.com/AI Security/ghostjacking-ai-agent-poisoned-observability-logs-august-2026

● FlawOpen 映射: CWE-1427 · 编辑严重性评级: 中危
安全研究 · FlawOpen

GhostJacking:日志与 AI 代理

研究展示了攻击者控制的遥测内容如何影响已连接的 AI 代理。目前没有 CVE,也没有确认发生受害者系统入侵。这是受控研究演示。[1], [2]

💡 通俗易懂的原理解析 (ELI5)

想象一下,前台人员拦下了可疑包裹,却把寄件人的留言原样记入事件日志。之后,调度员核实了真实的工单编号和演示测试配置中的 DNS 策略确实存在的缺口,于是相信同一条留言里由攻击者指定的地址,并修改公共地址簿(DNS),让浏览器和邮件系统把公司服务解析到那里。日志只是证据,不是修改权限;这项变更必须经过独立的策略检查和审批。[1]

核心概念与专有名词

GhostJacking
Tenet Security 对一类演示的称呼:攻击者控制的可观测性事件内容影响连接到这些工具的 AI 代理。这是研究名称,不是 CVE。[1], [2]
间接提示注入
指令被嵌入模型要检查的数据中,而不是由用户直接提供给模型。[1], [2], [4]
可观测性事件
描述系统活动的日志、告警、跟踪或错误记录。某些字段可能包含外部请求提供的文本。[1], [2]
独立授权
在模型之外执行的策略检查;工具采取重要操作前,检查操作者、目标、请求的更改和审批。[2], [5]
CWE-1427
MITRE 关于 LLM 提示输入处理不当的弱点类别。这是 FlawOpen 的概念映射;Tenet、ngCERT 和 CVE 记录均未将此编号分配给 GhostJacking。[4], [1], [2]
编辑严重性评级
ngCERT 将公告中的风险和损害评级为高。FlawOpen 将本文评为中等,因为演示需要代理具备相关集成和修改权限;目前没有确认的受害者入侵事件。这是编辑评级,不是厂商评分。[2], [1]

框架映射

攻击执行流程分解

步骤 1

代理获得调查权限

Tenet 的研究描述了连接 Cloudflare、Datadog 和 Sentry 等工具的编程或运维代理。关键前提是:代理既能读取外部事件内容,也能使用现有权限执行有后果的操作。[1]

步骤 2

请求被记录为证据

在 Tenet 的 Cloudflare 演示中,WAF 阻止了一条请求,但攻击者可控的请求字段仍被保留在事件记录中。请求即使被阻止,也可能留下供代理稍后读取的不可信文本。[1], [2]

步骤 3

看似可信的遥测信息绕过对明显指令的防护

Tenet 称,其测试中的明显命令式内容会被拒绝。其成功的 Cloudflare 演示改用结构化、类似扫描器输出的遥测信息,其中包含工单编号、合规性引用和指标;代理核实了部分说法,随后却信任了攻击者控制且未经核实的 DNS 值。这是研究人员报告的间接提示注入演示,并非真实受害者遭到入侵的证据。[1], [2]

步骤 4

现有权限将影响变成实际后果

Tenet 表示,其受控演示使代理通过集成的 Cloudflare 工具修改了 DNS。结果取决于代理权限和配置;这并不证明 Cloudflare 本身遭到入侵,也不证明客户系统遭到攻击。[1]

步骤 5

独立策略边界可以阻止更改

应用应将模型提出的更改视为不可信。服务器端授权服务必须独立核验具体资源和更改,适用时要求获授权人员批准,并在调用提供商 API 前记录决定。[2], [5]

源代码对比:漏洞与安全实现

这些片段是应用层示例,并非任何所述产品的漏洞或修复源代码。不安全的结构让读取不可信事件文本的代理直接使用修改工具。安全结构将提议与执行分开:独立服务使用绑定到具体操作者和更改内容的一次性审批,然后在调用服务商前应用策略。操作者身份来自经过认证的服务器上下文,而不是调用方可控制的字段;模型无法选择该身份。单靠 prompt 指令不是授权控制。生产代码还必须校验数据模式、租户和资源所有权、审批过期时间、重放防护、审计持久性和服务商错误。[1], [2], [5]

存在漏洞的实现
// 不安全集成的示意代码;并非 Cloudflare、Datadog、Sentry 或 Tenet 的源代码。
async function investigate(event: EventRecord) {
  return agent.run({
    context: event.message,
    tools: [cloudflare.updateDnsRecord]
  });
}
加固后的安全修复
// 控制边界示意;模型可以提出更改,但不能授权或执行。
type DnsProposal = { zoneId: string; name: string; value: string };

async function proposeDnsChange(event: EventRecord): Promise<DnsProposal> {
  return agent.propose({ evidence: markUntrusted(event.message) });
}

async function applyDnsChange(
  proposal: DnsProposal,
  approvalId: string
) {
  const actorId = auth.requireAuthenticatedActorId();
  const validatedProposal = DnsProposalSchema.parse(proposal);
  const approval = await approvals.consumeOnce(approvalId, { actorId });
  if (!approval || approval.actorId !== actorId ||
      approval.zoneId !== validatedProposal.zoneId ||
      approval.name !== validatedProposal.name ||
      approval.value !== validatedProposal.value ||
      !policy.canChangeDns(actorId, validatedProposal.zoneId, validatedProposal.name)) {
    throw new Error('DNS change is not independently authorized');
  }
  // 如果无法在修改前记录授权决定,则默认拒绝操作。
  await audit.record({ actorId, approvalId, action: 'dns-change', decision: 'authorized' });
  try {
    await cloudflare.updateDnsRecord(validatedProposal);
  } catch (error) {
    await audit.record({ actorId, approvalId, action: 'dns-change', outcome: 'provider-failed' });
    throw error;
  }
  await audit.record({ actorId, approvalId, action: 'dns-change', outcome: 'succeeded' });
}

工程与系统安全加固清单

参考来源

← AI Security Directory →