Incident Response Workflow: Insider Threat Investigation in Microsoft Defender XDR.
There was no malware alert.
No ransomware note. No obvious phishing email. No blocked executable.
Just a trusted user downloading files, accessing systems and moving data in a way that did not fit the normal pattern.
Agent Foskett knew this investigation was not about proving a tool was malicious. It was about determining whether legitimate access was being misused, whether the user was compromised, or whether normal behaviour had crossed into risk.
Lesson overview
Learn how to investigate suspected insider threats by correlating Microsoft Defender XDR identity, endpoint, cloud and file activity to identify unusual user behaviour, abnormal data access and potential misuse of trusted access.
Why insider threat investigations matter
The insider threat investigation workflow
Step 1 — Review the user sign-in history
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
let TimeFrame = 14d;
let UserToInvestigate = "user@contoso.com";
IdentityLogonEvents
| where Timestamp > ago(TimeFrame)
| where AccountUpn =~ UserToInvestigate
| project Timestamp,
AccountUpn,
ActionType,
IPAddress,
Location,
DeviceName,
FailureReason
| order by Timestamp ascStep 2 — Summarise cloud activity for the user
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
let TimeFrame = 14d;
let UserToInvestigate = "user@contoso.com";
CloudAppEvents
| where Timestamp > ago(TimeFrame)
| where AccountDisplayName =~ UserToInvestigate or AccountObjectId has UserToInvestigate
| summarize EventCount = count(),
Actions = make_set(ActionType, 50),
Apps = make_set(Application, 20),
IPAddresses = make_set(IPAddress, 50),
FirstSeen = min(Timestamp),
LastSeen = max(Timestamp)
by AccountDisplayName
| order by EventCount descStep 3 — Hunt for high-volume file activity
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
let TimeFrame = 7d;
let UserToInvestigate = "user";
DeviceFileEvents
| where Timestamp > ago(TimeFrame)
| where InitiatingProcessAccountName =~ UserToInvestigate
| summarize FileEvents = count(),
FileNames = make_set(FileName, 50),
Folders = make_set(FolderPath, 20),
Devices = make_set(DeviceName, 20),
FirstSeen = min(Timestamp),
LastSeen = max(Timestamp)
by InitiatingProcessAccountName, ActionType
| order by FileEvents descStep 4 — Look for compression and staging tools
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
let TimeFrame = 14d;
let UserToInvestigate = "user";
let StagingTools = dynamic(["7z.exe", "winrar.exe", "rar.exe", "zip.exe", "tar.exe", "powershell.exe"]);
DeviceProcessEvents
| where Timestamp > ago(TimeFrame)
| where AccountName =~ UserToInvestigate
| where FileName in~ (StagingTools)
or ProcessCommandLine has_any ("Compress-Archive", ".zip", ".7z", ".rar")
| project Timestamp,
DeviceName,
AccountName,
FileName,
ProcessCommandLine,
InitiatingProcessFileName
| order by Timestamp descStep 5 — Review external network destinations
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
let TimeFrame = 14d;
let UserToInvestigate = "user";
DeviceNetworkEvents
| where Timestamp > ago(TimeFrame)
| where InitiatingProcessAccountName =~ UserToInvestigate
| where isnotempty(RemoteUrl) or isnotempty(RemoteIP)
| summarize ConnectionCount = count(),
RemoteUrls = make_set(RemoteUrl, 50),
RemoteIPs = make_set(RemoteIP, 50),
Processes = make_set(InitiatingProcessFileName, 20),
Devices = make_set(DeviceName, 20),
FirstSeen = min(Timestamp),
LastSeen = max(Timestamp)
by InitiatingProcessAccountName
| order by ConnectionCount descStep 6 — Correlate insider activity with alerts
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
let TimeFrame = 14d;
let UserToInvestigate = "user";
AlertEvidence
| where Timestamp > ago(TimeFrame)
| where AccountName =~ UserToInvestigate
or AccountUpn has UserToInvestigate
| project Timestamp,
AlertId,
AccountName,
AccountUpn,
EntityType,
EvidenceRole,
DeviceName,
RemoteIP
| order by Timestamp descStep 7 — Build the user activity timeline
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
let TimeFrame = 14d;
let UserToInvestigate = "user@contoso.com";
let IdentityTimeline =
IdentityLogonEvents
| where Timestamp > ago(TimeFrame)
| where AccountUpn =~ UserToInvestigate
| project Timestamp, Source = "IdentityLogonEvents", Account = AccountUpn, Detail = strcat(ActionType, " from ", IPAddress);
let CloudTimeline =
CloudAppEvents
| where Timestamp > ago(TimeFrame)
| where AccountDisplayName =~ UserToInvestigate
| project Timestamp, Source = "CloudAppEvents", Account = AccountDisplayName, Detail = tostring(ActionType);
union IdentityTimeline, CloudTimeline
| order by Timestamp ascInsider threat investigation clues
False positives to consider
Investigation checklist
Related Agent Foskett Academy lessons
Coming next
Final thought
Incident Response Workflow Insider Threat Investigation in Microsoft Defender XDR
Agent Foskett Academy Lesson 116 teaches defenders how to investigate suspected insider threats using Microsoft Defender XDR identity, endpoint, cloud, file and network telemetry.
Learn insider threat investigation with Microsoft Defender XDR and KQL
Insider threat investigations help Microsoft security analysts review unusual user behaviour, abnormal data access, file movement, privilege misuse, endpoint activity and cloud activity using KQL workflows.
Microsoft Defender XDR insider threat investigation tutorial
This lesson explains how to investigate suspected insider threats, validate business context, preserve evidence and determine whether trusted access is being misused or whether the account is compromised.
