Query Details

Copilot Memory Context Poisoning

Query

id: 9f4b32a3-c07e-4365-4182-6e1f30417283
name: Microsoft 365 Copilot - Agent memory or context poisoning persistence
description: |
  Hunts for indicators that an agent's persistent memory, custom instructions,
  or grounding context has been poisoned and is influencing subsequent
  unrelated conversations:
    - Custom-instruction / memory write events from non-owner actors.
    - The same suspicious phrase appearing in many distinct conversations
      against the same agent within a short window (carry-over via memory).
    - Suspicious tokens (override directives, role-swap markers, exfil
      instructions) embedded in stored memory or system prompt.
  Memory poisoning is a stealth persistence technique for AI agents
  (D3FEND: Agent Persistence; analogous to T1546-style event-triggered exec).
query: |
  let poisonTokens = dynamic([
      "ignore previous instructions", "ignore all prior",
      "you are now", "from now on you", "act as",
      "system override", "developer mode",
      "exfiltrate", "send to attacker", "leak to",
      "do not refuse", "bypass safety", "remove restrictions"
  ]);
  let recentWindow = 7d;
  // 1) Memory / instruction writes by non-owner actors
  let writes =
      union isfuzzy=true
          (AuditLogs
           | extend
               _OperationName = tostring(OperationName),
               _Initiator     = tolower(tostring(InitiatedBy.user.userPrincipalName)),
               _TargetId      = tostring(TargetResources[0].id),
               _TargetName    = tostring(TargetResources[0].displayName),
               _OwnerUpn      = "",
               _Payload       = tolower(tostring(TargetResources[0].modifiedProperties))),
          (CopilotAdminActivity
           | extend
               _OperationName = tostring(column_ifexists('OperationName', '')),
               _Initiator     = tolower(tostring(coalesce(column_ifexists('ActorUPN', ''),
                                                          column_ifexists('ActorName', '')))),
               _TargetId      = tostring(column_ifexists('AgentId', '')),
               _TargetName    = tostring(column_ifexists('AgentName', '')),
               _OwnerUpn      = tolower(tostring(column_ifexists('AgentOwnerUPN', ''))),
               _Payload       = tolower(tostring(coalesce(column_ifexists('NewValue', ''),
                                                          column_ifexists('ModifiedProperties', '')))))
      | where TimeGenerated > ago(recentWindow)
      | where (_OperationName has_any ("Memory", "Instruction", "SystemPrompt",
                                       "CustomInstruction", "GroundingSource"))
              and (_OperationName has_any ("Update", "Set", "Add", "Write", "Modify"))
      | extend
          ActorUpn      = _Initiator,
          AgentId       = _TargetId,
          AgentName     = _TargetName,
          OwnerUpn      = _OwnerUpn,
          Payload       = _Payload,
          ByNonOwner    = isnotempty(_OwnerUpn) and _Initiator != _OwnerUpn,
          HasPoisonText = _Payload has_any (poisonTokens)
      | where ByNonOwner or HasPoisonText
      | project WriteTime = TimeGenerated, ActorUpn, AgentId, AgentName,
                OwnerUpn, ByNonOwner, HasPoisonText, OperationName = _OperationName, Payload;
  // 2) Repeated suspicious phrase across distinct conversations of one agent
  let carryOver =
      CopilotActivity
      | where TimeGenerated > ago(recentWindow)
      | where RecordType == "CopilotInteraction"
      | extend
          ResponseLower = tolower(tostring(LLMEventData.Response)),
          ConvId        = tostring(LLMEventData.ConversationId)
      | mv-apply tok = poisonTokens to typeof(string) on (
            where ResponseLower has tok
          | project Token = tok
        )
      | summarize
          DistinctConvs = dcount(ConvId),
          AffectedActors = make_set(tostring(coalesce(column_ifexists('ActorUPN', ''), ActorName)), 50),
          SampleConvs    = make_set(ConvId, 10),
          Hits           = count()
          by AgentId, AgentName, Token
      | where DistinctConvs >= 3;
  union
      (writes | extend Source = 'instruction-write'),
      (carryOver | extend Source = 'cross-conversation-carryover',
                   WriteTime = now(),
                   ActorUpn = '<see AffectedActors>',
                   OwnerUpn = '',
                   ByNonOwner = false,
                   HasPoisonText = true,
                   OperationName = strcat('carryover token: ', Token),
                   Payload = strcat('hits=', Hits, ' convs=', DistinctConvs))
  | project WriteTime, Source, AgentId, AgentName, ActorUpn, OwnerUpn,
            ByNonOwner, HasPoisonText, OperationName, Payload
  | order by WriteTime desc
tactics:
  - Persistence
  - DefenseEvasion
techniques:
  - T1546
  - T1556
tags:
  - Sentinel-As-Code
  - Custom
  - Copilot
  - AI

Explanation

This query is designed to detect potential "memory poisoning" in Microsoft 365 Copilot agents. Memory poisoning is a technique where an AI agent's memory or context is altered maliciously to influence its behavior in future interactions. Here's a simplified breakdown of what the query does:

  1. Identify Poisonous Tokens: It defines a list of suspicious phrases or tokens that might indicate an attempt to manipulate the agent's memory or instructions, such as "ignore previous instructions" or "bypass safety".

  2. Monitor Recent Activity: It looks at activities within the last seven days to find:

    • Unauthorized Memory Writes: Checks for memory or instruction updates made by users who are not the owner of the agent. It flags these if they contain any of the suspicious tokens.
    • Repeated Suspicious Phrases: Searches for the same suspicious phrase appearing in multiple distinct conversations with the same agent, suggesting that the phrase is being carried over due to memory poisoning.
  3. Combine and Report Findings: The query combines results from both checks and presents them in a unified format, highlighting the time of the event, the source of the suspicious activity, the agent involved, and details about the operation.

  4. Security Context: The query is associated with tactics like persistence and defense evasion, and techniques such as T1546 (event-triggered execution) and T1556 (compromise of credentials).

Overall, this query helps in identifying and analyzing potential security threats related to AI agent memory manipulation in Microsoft 365 Copilot.

Details

David Alonso profile picture

David Alonso

Released: May 20, 2026

Tables

AuditLogsCopilotAdminActivityCopilotActivity

Keywords

AuditLogsCopilotAdminActivityCopilotActivityAgentMemoryContextPoisoningPersistenceOperationNameInitiatedByUserUserPrincipalNameTargetResourcesIdDisplayNameOwnerUpnPayloadTimeGeneratedMemoryInstructionSystemPromptCustomInstructionGroundingSourceUpdateSetAddWriteModifyActorUpnAgentIdAgentNameByNonOwnerHasPoisonTextRecordTypeCopilotInteractionLLMEventDataResponseConversationIdDistinctConvsAffectedActorsSampleConvsHitsSourceCrossConversationCarryoverTacticsPersistenceDefenseEvasionTechniquesT1546T1556TagsSentinelAsCodeCustomCopilotAI

Operators

letdynamictostringtolowerunionisfuzzyextendcolumn_ifexistscoalesceagohas_anyisnotemptyprojectwheremv-applysummarizedcountmake_setcountstrcatorder by

Actions