Hunting Playbook: Malicious Inbox Rules in Microsoft Defender XDR.
The user said emails were missing.
Customers had replied. Invoices had arrived. Password reset messages had been sent.
But nothing appeared in the inbox.
Agent Foskett knew this was not just an email problem.
It was a post-compromise persistence problem.

Lesson overview
Learn how to hunt for malicious inbox rules created after mailbox compromise, including hidden forwarding, deletion rules, suspicious move rules and post-compromise mailbox persistence.
Why malicious inbox rules matter
The malicious inbox rule hunting workflow
Step 1 — Review recent cloud activity for mailbox rule changes
- 1
- 2
- 3
- 4
- 5
- 6
- 7
let TimeFrame = 14d;
CloudAppEvents
| where Timestamp > ago(TimeFrame)
| where ActionType has_any ("New-InboxRule", "Set-InboxRule", "UpdateInboxRules", "CreateInboxRule")
or ActivityType has_any ("New-InboxRule", "Set-InboxRule", "UpdateInboxRules", "CreateInboxRule")
| project Timestamp, AccountDisplayName, AccountId, ActionType, ActivityType, IPAddress, Application, RawEventData
| order by Timestamp descStep 2 — Search for forwarding or redirect behaviour
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
let TimeFrame = 30d;
let SuspiciousRuleTerms = dynamic(["forward", "redirect", "delete", "invoice", "payment", "password", "mfa", "verify"]);
CloudAppEvents
| where Timestamp > ago(TimeFrame)
| where ActionType has_any ("New-InboxRule", "Set-InboxRule", "UpdateInboxRules", "CreateInboxRule")
or ActivityType has_any ("New-InboxRule", "Set-InboxRule", "UpdateInboxRules", "CreateInboxRule")
| extend RuleData = tostring(RawEventData)
| where RuleData has_any (SuspiciousRuleTerms)
| project Timestamp, AccountDisplayName, IPAddress, ActionType, ActivityType, RuleData
| order by Timestamp descStep 3 — Identify accounts with recent suspicious rule changes
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
let TimeFrame = 30d;
CloudAppEvents
| where Timestamp > ago(TimeFrame)
| where ActionType has_any ("New-InboxRule", "Set-InboxRule", "UpdateInboxRules", "CreateInboxRule")
or ActivityType has_any ("New-InboxRule", "Set-InboxRule", "UpdateInboxRules", "CreateInboxRule")
| summarize RuleChangeCount = count(), SourceIPs = make_set(IPAddress, 20), Applications = make_set(Application, 20), FirstSeen = min(Timestamp), LastSeen = max(Timestamp) by AccountDisplayName
| order by RuleChangeCount descStep 4 — Correlate mailbox rule changes with suspicious sign-ins
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
let TimeFrame = 30d;
let RuleChanges =
CloudAppEvents
| where Timestamp > ago(TimeFrame)
| where ActionType has_any ("New-InboxRule", "Set-InboxRule", "UpdateInboxRules", "CreateInboxRule")
or ActivityType has_any ("New-InboxRule", "Set-InboxRule", "UpdateInboxRules", "CreateInboxRule")
| project RuleTime = Timestamp, AccountDisplayName, RuleChangeIP = IPAddress, RuleAction = ActionType, RuleActivity = ActivityType, RawEventData;
let SignIns =
IdentityLogonEvents
| where Timestamp > ago(TimeFrame)
| project SignInTime = Timestamp, AccountUpn, SignInIP = IPAddress, Location, SignInAction = ActionType, FailureReason;
RuleChanges
| join kind=leftouter SignIns on $left.AccountDisplayName == $right.AccountUpn
| where SignInTime between ((RuleTime - 6h) .. (RuleTime + 6h))
| project RuleTime, SignInTime, AccountDisplayName, RuleChangeIP, SignInIP, Location, RuleAction, RuleActivity, SignInAction, FailureReason
| order by RuleTime descStep 5 — Look for mailbox access after rule creation
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
let TimeFrame = 30d;
let RuleChangeUsers =
CloudAppEvents
| where Timestamp > ago(TimeFrame)
| where ActionType has_any ("New-InboxRule", "Set-InboxRule", "UpdateInboxRules", "CreateInboxRule")
or ActivityType has_any ("New-InboxRule", "Set-InboxRule", "UpdateInboxRules", "CreateInboxRule")
| summarize FirstRuleChange = min(Timestamp) by AccountDisplayName;
CloudAppEvents
| where Timestamp > ago(TimeFrame)
| join kind=inner RuleChangeUsers on AccountDisplayName
| where Timestamp >= FirstRuleChange
| summarize PostRuleActivity = count(), ActivityTypes = make_set(ActivityType, 30), Applications = make_set(Application, 20), SourceIPs = make_set(IPAddress, 20), FirstActivity = min(Timestamp), LastActivity = max(Timestamp) by AccountDisplayName, FirstRuleChange
| order by PostRuleActivity descStep 6 — Build the malicious inbox rule timeline
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
let TimeFrame = 30d;
let TargetUser = "user@contoso.com";
let RuleActivity =
CloudAppEvents
| where Timestamp > ago(TimeFrame)
| where AccountDisplayName =~ TargetUser
| where ActionType has_any ("New-InboxRule", "Set-InboxRule", "UpdateInboxRules", "CreateInboxRule")
or ActivityType has_any ("New-InboxRule", "Set-InboxRule", "UpdateInboxRules", "CreateInboxRule")
| project Timestamp, EventType = "Mailbox rule activity", Account = AccountDisplayName, IPAddress, Detail = strcat(ActionType, " ", ActivityType);
let SignInActivity =
IdentityLogonEvents
| where Timestamp > ago(TimeFrame)
| where AccountUpn =~ TargetUser
| project Timestamp, EventType = "Identity sign-in", Account = AccountUpn, IPAddress, Detail = strcat(ActionType, " ", FailureReason);
union RuleActivity, SignInActivity
| order by Timestamp ascCommon malicious inbox rule behaviours
Common false positives
Evidence that increases suspicion
Investigation checklist
Related Agent Foskett Academy lessons
Coming next
Final thought
Hunting Playbook Malicious Inbox Rules in Microsoft Defender XDR
Agent Foskett Academy Lesson 103 teaches defenders how to hunt for malicious inbox rules using Microsoft Defender XDR, Exchange Online telemetry, CloudAppEvents, mailbox rule changes and identity sign-in evidence.
Investigate malicious inbox rules with KQL and Microsoft Defender XDR
Malicious inbox rules are a common post-compromise technique used in Microsoft 365 business email compromise investigations. Defenders can detect forwarding, deletion, move rules and hidden mailbox activity by correlating mailbox telemetry and identity events.
Microsoft 365 malicious inbox rule investigation playbook
This hunting playbook explains how to investigate suspicious inbox rules, external forwarding, hidden deletion rules, compromised mailboxes, suspicious sign-ins and post-compromise persistence in Microsoft Defender XDR.
