ID | Technique | Tactic |
---|---|---|
T1078 | Valid Accounts | Defense Evasion |
Detection: M365 Copilot Application Usage Pattern Anomalies
Description
Detects M365 Copilot users exhibiting suspicious application usage patterns including multi-location access, abnormally high activity volumes, or access to multiple Copilot applications that may indicate account compromise or automated abuse. The detection aggregates M365 Copilot Graph API events per user, calculating metrics like distinct cities/countries accessed, unique IP addresses, number of different Copilot apps used, and average events per day over the observation period. Users are flagged when they access Copilot from multiple cities (cities_count > 1), generate excessive daily activity (events_per_day > 100), or use more than two different Copilot applications (app_count > 2), which are anomalous patterns suggesting credential compromise or bot-driven abuse.
Search
1`m365_copilot_graph_api` (appDisplayName="*Copilot*" OR appDisplayName="M365ChatClient" OR appDisplayName="OfficeAIAppChatCopilot")
2| eval user = userPrincipalName
3| stats count as events,
4 dc(location.city) as cities_count,
5 values(location.city) as city_list,
6 dc(location.countryOrRegion) as countries_count,
7 values(location.countryOrRegion) as country_list,
8 dc(ipAddress) as ip_count,
9 values(ipAddress) as ip_addresses,
10 dc(appDisplayName) as app_count,
11 values(appDisplayName) as apps_used,
12 dc(resourceDisplayName) as resource_count,
13 values(resourceDisplayName) as resources_accessed,
14 min(_time) as first_seen,
15 max(_time) as last_seen
16 by user
17
18| eval days_active = round((last_seen - first_seen)/86400, 1)
19| eval first_seen = strftime(first_seen, "%Y-%m-%d %H:%M:%S")
20| eval last_seen = strftime(last_seen, "%Y-%m-%d %H:%M:%S")
21| eval events_per_day = if(days_active > 0, round(events/days_active, 2), events)
22| where cities_count > 1 OR events_per_day > 100 OR app_count > 2
23| sort -events_per_day, -countries_count
24| `m365_copilot_application_usage_pattern_anomalies_filter`
Data Source
Name | Platform | Sourcetype | Source |
---|---|---|---|
M365 Copilot Graph API | N/A | 'o365:graph:api' |
'AuditLogs.SignIns' |
Macros Used
Name | Value |
---|---|
m365_copilot_graph_api | (sourcetype="o365:graph:api" OR source="AuditLogs.SignIns") |
m365_copilot_application_usage_pattern_anomalies_filter | search * |
m365_copilot_application_usage_pattern_anomalies_filter
is an empty macro by default. It allows the user to filter out any results (false positives) without editing the SPL.
Annotations
Default Configuration
This detection is configured by default in Splunk Enterprise Security to run with the following settings:
Setting | Value |
---|---|
Disabled | true |
Cron Schedule | 0 * * * * |
Earliest Time | -70m@m |
Latest Time | -10m@m |
Schedule Window | auto |
Creates Risk Event | True |
Implementation
This detection requires ingesting M365 Copilot access logs via the Splunk Add-on for Microsoft Office 365. Configure the add-on to collect Azure AD Sign-in logs (AuditLogs.SignIns) through the Graph API data input. Ensure proper authentication and permissions are configured to access sign-in audit logs. The m365_copilot_graph_api
macro should be defined to filter for sourcetype o365:graph:api data containing Copilot application activity.
Known False Positives
Power users, executives with heavy AI workloads, employees traveling for business, users accessing multiple Copilot applications legitimately, or teams using shared corporate accounts across different office locations may trigger false positives.
Associated Analytic Story
Risk Based Analytics (RBA)
Risk Message:
User $user$ exhibited anomalous M365 Copilot usage patterns including multi-location access, excessive activity levels, or multiple application usage indicating potential account compromise or automated abuse.
Risk Object | Risk Object Type | Risk Score | Threat Objects |
---|---|---|---|
user | user | 10 | No Threat Objects |
References
Detection Testing
Test Type | Status | Dataset | Source | Sourcetype |
---|---|---|---|---|
Validation | ✅ Passing | N/A | N/A | N/A |
Unit | ✅ Passing | Dataset | AuditLogs.SignIns |
o365:graph:api |
Integration | ✅ Passing | Dataset | AuditLogs.SignIns |
o365:graph:api |
Replay any dataset to Splunk Enterprise by using our replay.py
tool or the UI.
Alternatively you can replay a dataset into a Splunk Attack Range
Source: GitHub | Version: 1