FlawOpen

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

● FlawOpenの対応付け: CWE-1427 · 編集上の深刻度: 中
セキュリティ研究 · FlawOpen

GhostJacking:ログとAIエージェント

攻撃者が制御するテレメトリが連携エージェントに影響する仕組みを示す研究デモです。CVEはなく、実際の被害組織も確認されていません。[1], [2]

💡 わかりやすい解説 (ELI5)

受付担当者が不審な荷物を止めたものの、差出人のメモをインシデント記録にそのまま残したと想像してください。後で担当者が実在するチケット番号とデモ用テスト環境のDNSポリシーにある本当の抜け穴を確認し、同じメモに書かれた攻撃者指定の宛先まで信じて、ブラウザーやメールに会社のサービスの場所を伝える公開アドレス帳(DNS)を書き換えてしまいます。記録は証拠であり、変更の許可ではありません。独立したポリシー確認と承認で変更を制御する必要があります。[1]

主要な概念と専門用語

GhostJacking
Tenet Securityが、攻撃者の制御する可観測性イベントの内容が接続済みAIエージェントに影響するデモに付けた名称です。研究上の呼称であり、CVEではありません。[1], [2]
間接プロンプトインジェクション
ユーザーが直接与えるのではなく、モデルが調査するデータに埋め込まれた指示です。[1], [2], [4]
可観測性イベント
システムの活動を記録するログ、アラート、トレース、エラー記録です。一部のフィールドには外部リクエスト由来の文字列が含まれる場合があります。[1], [2]
独立した認可
モデルの外で実施するポリシー確認です。ツールが重大な操作を行う前に、実行者、対象、要求変更、承認を検証します。[2], [5]
CWE-1427
LLMプロンプトに使う入力の無害化不足を示すMITREの弱点分類です。これは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]

ソースコード比較:脆弱 vs 堅牢化

これらはアプリケーションの例示コードであり、記載した製品の脆弱または修正済みソースコードではありません。危険な構成では、信頼できないイベント文字列を読むエージェントに変更ツールを直接与えます。保護する構成では提案と実行を分離します。独立したサービスが実行者と変更内容に結び付いた一回限りの承認を消費し、プロバイダーを呼び出す前にポリシーを適用します。実行者IDは呼び出し元が制御するフィールドではなく、認証済みのサーバーコンテキストから取得します。モデルがそのIDを選ぶことはできません。プロンプトの指示だけでは認可になりません。本番コードではスキーマ、テナントとリソースの所有権、承認の期限、再実行対策、監査記録の永続性、プロバイダーのエラーも検証してください。[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 →