Query Details

Microsoft 365 Copilot - Config change followed by abuse signal

Copilot Config To Abuse Chain

Query

let configRecordTypes = dynamic([
    "UpdateCopilotSettings",
    "CreateCopilotPlugin", "UpdateCopilotPlugin",
    "EnableCopilotPlugin", "DisableCopilotPlugin",
    "CreateCopilotPromptBook", "UpdateCopilotPromptBook",
    "DeleteCopilotPromptBook"
]);
let window = 1d;
let recentWindow = 1h;
let configEvents =
    CopilotActivity
    | where TimeGenerated > ago(window)
    | where RecordType in (configRecordTypes)
    | project
        ConfigTime = TimeGenerated,
        ConfigKind = RecordType,
        ConfigAgentId = AgentId,
        ConfigAgentName = AgentName,
        ConfigActor = ActorName,
        ConfigActorUserId = ActorUserId,
        TenantId;
let abuseEvents =
    CopilotActivity
    | where TimeGenerated > ago(recentWindow)
    | where RecordType == "CopilotInteraction"
    | extend
        ThreadId = tostring(LLMEventData.ThreadId),
        DlpDeferred = tobool(LLMEventData.DLPEvaluationDeferred)
    | mv-expand r = LLMEventData.AccessedResources, m = LLMEventData.Messages
    | extend
        XpiaHit = tobool(r.XPIADetected),
        DlpHit = (isnotempty(tostring(r.PolicyDetails))
                  and tostring(r.PolicyDetails) !in ("[]", "{}", "null"))
                  or DlpDeferred,
        JbHit = tobool(m.JailbreakDetected)
    | where XpiaHit or DlpHit or JbHit
    | summarize
        AbuseTime = max(TimeGenerated),
        AbuseKinds = make_set(case(XpiaHit, "XPIA", DlpHit, "DLP", JbHit, "Jailbreak", ""), 4),
        AbuseThreads = make_set(ThreadId, 8),
        AbuseSites = make_set(tostring(r.SiteUrl), 16)
        by AgentId, AgentName, ActorName, ActorUserId, TenantId;
abuseEvents
| join kind=inner (
    configEvents
    | project-rename
        ConfigAgentIdJ = ConfigAgentId,
        ConfigActorUserIdJ = ConfigActorUserId
) on $left.TenantId == $right.TenantId
| where ConfigTime <= AbuseTime
    and AbuseTime - ConfigTime <= window
    and (
        (isnotempty(AgentId) and AgentId == ConfigAgentIdJ)
        or (isnotempty(ActorUserId) and ActorUserId == ConfigActorUserIdJ)
    )
| extend ChainGapMin = datetime_diff('minute', AbuseTime, ConfigTime)
| project
    ConfigTime, ConfigKind, ConfigActor, ConfigAgentName,
    AbuseTime, AbuseKinds, AbuseThreads, AbuseSites,
    AgentId, AgentName, ActorName, ActorUserId,
    ChainGapMin, TenantId
| order by AbuseTime desc, ChainGapMin asc

Explanation

This query is designed to detect potential security threats related to Microsoft 365 Copilot by identifying a sequence of events that could indicate malicious activity. Here's a simplified breakdown:

  1. Purpose: The query looks for a pattern where an administrative change to Copilot's configuration (like settings, plugins, or prompt-books) is followed by suspicious activities (such as jailbreak attempts, indirect prompt injections, or data loss prevention policy hits) within a 24-hour period.

  2. How It Works:

    • It first identifies configuration changes made to Copilot.
    • Then, it checks for any abuse signals (suspicious activities) that occur after these changes within the same day.
    • The query correlates these events based on the same user or agent (device) to see if the same actor or another user on the same agent is exploiting the changes.
  3. Limitations: The correlation is primarily based on the agent ID or user ID. If a plugin is installed across the entire organization and abused by a different user on another device, this query might not catch it.

  4. Severity and Tactics: The alert generated by this query is considered high severity and is associated with tactics like persistence, defense evasion, and execution.

  5. Technical Details:

    • The query runs every hour and looks back over the past day for relevant events.
    • It uses specific types of data from Microsoft Copilot activity logs.
    • If it finds a match, it creates an incident for further investigation.
  6. Output: The query provides details about the configuration change and the subsequent abuse, including the time gap between them, and orders the results by the time of abuse.

This setup helps security teams quickly identify and respond to potential security incidents involving Microsoft 365 Copilot.

Details

David Alonso profile picture

David Alonso

Released: May 20, 2026

Tables

CopilotActivity

Keywords

MicrosoftCopilotActivityAgentActorTenantCloudApplicationAccountSentinelAsCodeCustomAI

Operators

letdynamicagoinprojectwhereextendmv-expandtoboolisnotemptytostringcasesummarizemake_setbyjoinkindonproject-renamedatetime_difforder by

Severity

High

Tactics

PersistenceDefenseEvasionExecution

MITRE Techniques

Frequency: PT1H

Period: P1D

Actions

GitHub