Query Details

Copilot Plugin Install Anomaly

Query

id: 8e3a2192-bf6d-4254-3071-5d0e2f306172
name: Microsoft 365 Copilot - Plugin or connector install anomaly
description: |
  Hunts for new Microsoft 365 Copilot plugins / connectors / declarative
  agents enabled by an actor that has not previously installed any, or
  installed at a rate sharply higher than baseline. Catches:
  - Mass plugin enablement before exfiltration.
  - Installation of plugins absent from the CopilotApprovedPlugins watchlist.
  - User-consented plugins on a tenant that mandates admin consent.
query: |
  let lookback = 30d;
  let recentWindow = 1d;
  let pluginEvents =
      union isfuzzy=true
          (AuditLogs
           | extend
               _OperationName = tostring(OperationName),
               _RecordType    = "AuditLogs",
               _Initiator     = tolower(tostring(InitiatedBy.user.userPrincipalName)),
               _TargetName    = tostring(TargetResources[0].displayName)),
          (OfficeActivity
           | extend
               _OperationName = tostring(Operation),
               _RecordType    = tostring(RecordType),
               _Initiator     = tolower(tostring(UserId)),
               _TargetName    = tostring(coalesce(column_ifexists('ItemName', ''), Operation))),
          (CopilotAdminActivity
           | extend
               _OperationName = tostring(column_ifexists('OperationName', '')),
               _RecordType    = "CopilotAdminActivity",
               _Initiator     = tolower(tostring(coalesce(column_ifexists('ActorUPN', ''),
                                                          column_ifexists('ActorName', '')))),
               _TargetName    = tostring(coalesce(column_ifexists('PluginName', ''),
                                                  column_ifexists('ResourceName', ''))))
      | where TimeGenerated > ago(lookback)
      | where (_OperationName has_any ("Install", "Add", "Enable")
               and _OperationName has_any ("Plugin", "Connector", "Agent", "App", "Extension"))
              or _RecordType in ("MicrosoftCopilotAdminAction", "CopilotAdminActivity")
      | project TimeGenerated, ActorUpn = _Initiator, PluginName = _TargetName,
                LowerPlugin = tolower(_TargetName), _OperationName, _RecordType;
  let approved =
      _GetWatchlist('CopilotApprovedPlugins')
      | project ApprovedPlugin = tolower(tostring(column_ifexists('PluginName', '')))
      | where isnotempty(ApprovedPlugin);
  let baseline =
      pluginEvents
      | where TimeGenerated between (ago(lookback) .. ago(recentWindow))
      | summarize BaselineInstalls = count() by ActorUpn;
  let recent =
      pluginEvents
      | where TimeGenerated > ago(recentWindow)
      | summarize
          RecentInstalls   = count(),
          DistinctPlugins  = dcount(LowerPlugin),
          PluginSample     = make_set(PluginName, 25)
          by ActorUpn;
  recent
  | join kind=leftouter baseline on ActorUpn
  | extend BaselineInstalls = coalesce(BaselineInstalls, 0)
  | extend SpikeRatio = iff(BaselineInstalls > 0,
                            todouble(RecentInstalls) / todouble(BaselineInstalls),
                            todouble(RecentInstalls))
  | where (BaselineInstalls == 0 and RecentInstalls >= 3)
       or SpikeRatio >= 5.0
       or DistinctPlugins >= 5
  | join kind=leftouter (
        pluginEvents
        | where TimeGenerated > ago(recentWindow)
        | join kind=leftanti approved on $left.LowerPlugin == $right.ApprovedPlugin
        | summarize UnapprovedPlugins = make_set(PluginName, 25) by ActorUpn
    ) on ActorUpn
  | project TimeGenerated = now(), ActorUpn, RecentInstalls, BaselineInstalls,
            SpikeRatio, DistinctPlugins, PluginSample, UnapprovedPlugins
  | order by SpikeRatio desc, RecentInstalls desc
tactics:
  - Persistence
  - PrivilegeEscalation
techniques:
  - T1098
  - T1505
tags:
  - Sentinel-As-Code
  - Custom
  - Copilot
  - AI

Explanation

This query is designed to detect unusual activity related to the installation of Microsoft 365 Copilot plugins or connectors. Here's a simplified breakdown of what it does:

  1. Purpose: The query identifies anomalies in the installation of Microsoft 365 Copilot plugins or connectors. It looks for:

    • New plugins or connectors enabled by users who haven't installed any before.
    • A sudden increase in the installation rate compared to the user's past behavior.
    • Plugins that are not on an approved list.
    • User-consented plugins in environments where admin consent is required.
  2. Data Sources: It examines logs from various sources, including AuditLogs, OfficeActivity, and CopilotAdminActivity, to gather information about plugin-related operations.

  3. Time Frame: The query analyzes data from the past 30 days, with a focus on the most recent day to identify recent activities.

  4. Baseline and Recent Activity:

    • It calculates a baseline of plugin installations for each user over the past 30 days, excluding the most recent day.
    • It then looks at the number of installations in the most recent day.
  5. Anomaly Detection:

    • It flags users who have installed plugins for the first time and have installed three or more in the recent day.
    • It identifies users with a spike in installation activity, defined as five times the baseline rate.
    • It also flags users who have installed five or more distinct plugins.
  6. Unapproved Plugins: The query checks if any installed plugins are not on the approved list and highlights these.

  7. Output: The results include details such as the number of recent installations, baseline installations, spike ratio, distinct plugins, and any unapproved plugins. The results are sorted by the spike ratio and the number of recent installations.

  8. Security Context: The query is associated with tactics like persistence and privilege escalation, and techniques such as T1098 (Account Manipulation) and T1505 (Server Software Component).

Overall, this query helps in identifying potential security risks by monitoring unusual plugin installation activities in Microsoft 365 environments.

Details

David Alonso profile picture

David Alonso

Released: May 20, 2026

Tables

AuditLogsOfficeActivityCopilotAdminActivity

Keywords

MicrosoftCopilotPluginConnectorAgentAppExtensionAuditLogsOfficeActivityCopilotAdminActivityPluginNameResourceNameMicrosoftCopilotAdminActionActorUpnPluginSampleUnapprovedPluginsSentinelAsCodeCustomAI

Operators

letunionisfuzzyextendtostringtolowercoalescecolumn_ifexistswhereagohas_anyinproject_GetWatchlistisnotemptysummarizecountbetweendcountmake_setjoinkindleftouterleftantionextendcoalesceifftodoubleorder bydesc

Actions