EXPLORE
← Back to Explore
splunk_escuTTP

Microsoft Defender Incident Alerts

The following analytic is to leverage alerts from Microsoft Defender O365 Incidents. This query aggregates and summarizes all alerts from Microsoft Defender O365 Incidents, providing details such as the destination, file name, severity, process command line, ip address, registry key, signature, description, unique id, and timestamps. This detection is not intended to detect new activity from raw data, but leverages Microsoft provided alerts to be correlated with other data as part of risk based alerting. The data contained in the alert is mapped not only to the risk object, but also the threat object. This detection filters out evidence that has a verdict of clean from Microsoft. It dynamically maps the MITRE technique at search time to auto populate the annotation field with the value provided in the alert. It also uses a static mapping to set the risk score based on the severity of the alert.

Detection Query

`ms365_defender_incident_alerts`  (dest=* OR user=*)
  | eval tmp_entities=json_extract(_raw, "entities"), tmp_entitymv=json_array_to_mv(tmp_entities), tmp_filtered_mv=mvfilter(json_extract(tmp_entitymv, "verdict") != "Clean"), entityType = mvmap(tmp_filtered_mv, spath(tmp_filtered_mv, "entityType")), filePath = mvmap(tmp_filtered_mv, spath(tmp_filtered_mv, "filePath")), processCommandLine = mvmap(tmp_filtered_mv, spath(tmp_filtered_mv, "processCommandLine")), ipAddress = mvmap(tmp_filtered_mv, spath(tmp_filtered_mv, "ipAddress")), registryKey = mvmap(tmp_filtered_mv, spath(tmp_filtered_mv, "registryKey")), url = mvmap(tmp_filtered_mv, spath(tmp_filtered_mv, "url"))
  | eval tmp_filtered_mv=mvfilter(json_extract(tmp_filtered_mv, "entityType") = "File"), fileName = mvmap(tmp_filtered_mv, spath(tmp_filtered_mv, "fileName"))
  | eval risk_score=case(severity="informational", 5, severity="low", 15, severity="medium", 25, severity="high", 50, true(), 2)
  | stats count  min(_time) as firstTime max(_time) as lastTime values(fileName) as file_name values(severity) as severity values(processCommandLine) as process values(ipAddress) as ip_address values(registryKey) as registry_key values(url) as url values(mitreTechniques{}) as annotations.mitre_attack.mitre_technique_id values(signature) as signature values(dest) as dest values(user) as user values(risk_score) as risk_score
    BY id description
  | `security_content_ctime(firstTime)`
  | `security_content_ctime(lastTime)`
  | `microsoft_defender_incident_alerts_filter`

Author

Bryan Pluta, Bhavin Patel, Splunk, lyonheart14, Github Community

Created

2026-04-16

Data Sources

MS365 Defender Incident Alerts

Tags

Critical Alerts
Raw Content
name: Microsoft Defender Incident Alerts
id: 13435b55-afd8-46d4-9045-7d5457f430a5
version: 8
date: '2026-04-16'
author: Bryan Pluta, Bhavin Patel, Splunk, lyonheart14, Github Community
status: production
type: TTP
data_source:
    - MS365 Defender Incident Alerts
description: The following analytic is to leverage alerts from Microsoft Defender O365 Incidents. This query aggregates and summarizes all alerts from Microsoft Defender O365 Incidents, providing details such as the destination, file name, severity, process command line, ip address, registry key, signature, description, unique id, and timestamps. This detection is not intended to detect new activity from raw data, but leverages Microsoft provided alerts to be correlated with other data as part of risk based alerting. The data contained in the alert is mapped not only to the risk object, but also the threat object. This detection filters out evidence that has a verdict of clean from Microsoft. It dynamically maps the MITRE technique at search time to auto populate the annotation field with the value provided in the alert. It also uses a static mapping to set the risk score based on the severity of the alert.
search: "`ms365_defender_incident_alerts`  (dest=* OR user=*)\n  | eval tmp_entities=json_extract(_raw, \"entities\"), tmp_entitymv=json_array_to_mv(tmp_entities), tmp_filtered_mv=mvfilter(json_extract(tmp_entitymv, \"verdict\") != \"Clean\"), entityType = mvmap(tmp_filtered_mv, spath(tmp_filtered_mv, \"entityType\")), filePath = mvmap(tmp_filtered_mv, spath(tmp_filtered_mv, \"filePath\")), processCommandLine = mvmap(tmp_filtered_mv, spath(tmp_filtered_mv, \"processCommandLine\")), ipAddress = mvmap(tmp_filtered_mv, spath(tmp_filtered_mv, \"ipAddress\")), registryKey = mvmap(tmp_filtered_mv, spath(tmp_filtered_mv, \"registryKey\")), url = mvmap(tmp_filtered_mv, spath(tmp_filtered_mv, \"url\"))\n  | eval tmp_filtered_mv=mvfilter(json_extract(tmp_filtered_mv, \"entityType\") = \"File\"), fileName = mvmap(tmp_filtered_mv, spath(tmp_filtered_mv, \"fileName\"))\n  | eval risk_score=case(severity=\"informational\", 5, severity=\"low\", 15, severity=\"medium\", 25, severity=\"high\", 50, true(), 2)\n  | stats count  min(_time) as firstTime max(_time) as lastTime values(fileName) as file_name values(severity) as severity values(processCommandLine) as process values(ipAddress) as ip_address values(registryKey) as registry_key values(url) as url values(mitreTechniques{}) as annotations.mitre_attack.mitre_technique_id values(signature) as signature values(dest) as dest values(user) as user values(risk_score) as risk_score\n    BY id description\n  | `security_content_ctime(firstTime)`\n  | `security_content_ctime(lastTime)`\n  | `microsoft_defender_incident_alerts_filter`"
how_to_implement: In order to properly run this search, you need to ingest alerts data from Microsoft Defender, specifcally using the Splunk add-on for Microsoft Security. This add-on will collect alerts using the ms365:defender:incident:alerts sourcetype. You will need to define the `ms365_defender_incident_alerts` macro to point to the proper index that contains the ms365:defender:incident:alerts sourcetype.
known_false_positives: False positives may vary based on Microsoft Defender configuration; monitor and filter out the alerts that are not relevant to your environment.
references:
    - https://learn.microsoft.com/en-us/defender-xdr/api-list-incidents?view=o365-worldwide
    - https://learn.microsoft.com/en-us/graph/api/resources/security-alert?view=graph-rest-1.0
    - https://splunkbase.splunk.com/app/6207
    - https://jasonconger.com/splunk-azure-gdi/
drilldown_searches:
    - name: View the detection results for - "$dest$" and "$user$"
      search: '%original_detection_search% | search  dest = "$dest$" user = "$user$"'
      earliest_offset: $info_min_time$
      latest_offset: $info_max_time$
    - name: View risk events for the last 7 days for - "$dest$" and "$user$"
      search: '| from datamodel Risk.All_Risk | search normalized_risk_object IN ("$dest$","$user$") | stats count min(_time) as firstTime max(_time) as lastTime values(search_name) as "Search Name" values(risk_message) as "Risk Message" values(analyticstories) as "Analytic Stories" values(annotations._all) as "Annotations" values(annotations.mitre_attack.mitre_tactic) as "ATT&CK Tactics" by normalized_risk_object | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`'
      earliest_offset: 7d
      latest_offset: '0'
rba:
    message: $severity$ alert for $dest$ - $signature$
    risk_objects:
        - field: dest
          type: system
          score: 50
        - field: user
          type: user
          score: 50
    threat_objects:
        - field: file_name
          type: file_name
        - field: process
          type: process_name
        - field: ip_address
          type: ip_address
        - field: registry_key
          type: registry_path
        - field: url
          type: url
tags:
    analytic_story:
        - Critical Alerts
    asset_type: Endpoint
    atomic_guid: []
    mitre_attack_id: []
    product:
        - Splunk Enterprise
        - Splunk Enterprise Security
        - Splunk Cloud
    security_domain: endpoint
    manual_test: We are dynamically creating the risk_score field based on the severity of the alert in the SPL and that supersedes the risk score set in the detection. Setting these to manual test since otherwise we fail integration testing. The detection is also failing on unit-testing as some of the fields set in the observables are empty.
tests:
    - name: True Positive Test
      attack_data:
        - data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/suspicious_behaviour/alerts/defender_incident_alerts_single_event.log
          source: m365_defender_incident_alerts
          sourcetype: ms365:defender:incident:alerts