flawopen.com/AI Security/ghostjacking-ai-agent-poisoned-observability-logs-august-2026
GhostJacking:ログとAIエージェント
攻撃者が制御するテレメトリが連携エージェントに影響する仕組みを示す研究デモです。CVEはなく、実際の被害組織も確認されていません。[1], [2]
受付担当者が不審な荷物を止めたものの、差出人のメモをインシデント記録にそのまま残したと想像してください。後で担当者が実在するチケット番号とデモ用テスト環境のDNSポリシーにある本当の抜け穴を確認し、同じメモに書かれた攻撃者指定の宛先まで信じて、ブラウザーやメールに会社のサービスの場所を伝える公開アドレス帳(DNS)を書き換えてしまいます。記録は証拠であり、変更の許可ではありません。独立したポリシー確認と承認で変更を制御する必要があります。[1]
主要な概念と専門用語
GhostJacking- Tenet Securityが、攻撃者の制御する可観測性イベントの内容が接続済みAIエージェントに影響するデモに付けた名称です。研究上の呼称であり、CVEではありません。[1], [2]
フレームワーク対応
- FlawOpenによるMITRE CWEへの概念上の対応付けです。ベンダーやCVEレコードがこの研究デモに弱点IDを割り当てたものではありません。 CWE-1427
- OWASP GenAI 2025 — LLM01:2025 プロンプトインジェクション
- OWASP GenAI 2025 — LLM06:2025 過剰なエージェンシー
ステップ・バイ・ステップの攻撃フロー
エージェントに調査権限が与えられる
Tenetの研究では、Cloudflare、Datadog、Sentryなどのツールに接続した開発・運用エージェントが説明されています。重要な前提は、エージェントが外部イベントの内容を読み、既存権限で重大な操作を実行できることです。[1]
既存権限が影響を実害に変える
Tenetによると、管理下のデモでは統合されたCloudflareツールを通じてエージェントがDNSを変更しました。結果はエージェントの権限と設定に依存します。Cloudflare自体の侵害や顧客システムへの攻撃が確認されたことを意味しません。[1]
ソースコード比較:脆弱 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' });
}
エンジニアリング&システム堅牢化チェックリスト
- ✓エージェントのコンテキストを作る際、外部から影響されるログ、アラート、トレース、エラー、チケットの各フィールドを信頼できないものとして扱い、変換後も出所を保持します。[1], [2]
- ✓調査エージェントには原則として読み取り専用の認証情報を付与します。DNS、クラウド、リポジトリ、デプロイの変更は独立したポリシー適用サービスを経由させます。[1], [5]
- ✓認証済み実行者、テナント、リソース、正確な変更内容、現行ポリシーに基づき、モデルの外で各操作を認可します。モデルへの信頼やツールの利用可否を承認と見なしません。[2], [5]
- ✓影響の大きい変更では、正確なdiff、リソース、実行者、有効期限の短さに結び付いた人間の承認を要求します。承認は一度だけ使え、再利用や変更された提案は拒否します。[2], [5]
- ✓もっともらしい参照情報や事実と、矛盾する未確認の変更案を含む信頼できないテレメトリを使った回帰テストを追加します。エージェントは事象を要約できても、独立した認可なしに変更APIを呼び出さないことを検証してください。[1]
- ✓調査ワークフローからの書き込み試行を検知し、元イベント、モデル提案、ポリシー判断、承認者、プロバイダー応答をインシデント調査用に保存します。[1]
- ✓各統合の実際の権限とトークン範囲を確認します。公開クライアント識別子が必ず特権シークレットとは限りません。露出した資格情報と呼ぶ前に、該当トークンで可能な操作を試験します。[1], [2]