Why “bad” matters
Effective detection is not just about matching one event name. It is about understanding how identity, mailbox access, and user behavior change when an account is compromised.
Mailbox compromise detection flow
This flow helps turn scattered telemetry into a repeatable investigation path.
High-signal scenarios
Mailbox access without Outlook
Mailbox activity appears without normal Outlook, OWA, or mobile client behavior.
MFA success followed by compromise
The user completes MFA, but mailbox activity begins from a suspicious context shortly afterward.
High-volume mailbox reads
Hundreds of messages are accessed in minutes, suggesting automated data mining.
Login to inbox rule creation
A successful sign-in is quickly followed by a new forwarding or hiding rule.
Silent session activity
Mailbox access continues after a single login event without normal interactive behavior.
Client mismatch
The user normally uses Outlook, but activity appears from an unknown or API-like client.
Mailbox access without Outlook client
This hunt looks for mailbox access that does not appear to come from common Outlook, OWA, or mobile clients.
AuditLogs
| where Operation == "MailItemsAccessed"
| where ClientInfoString !has_any ("Outlook", "OWA", "Mobile")
| summarize AccessCount=count() by UserId, ClientInfoString
| where AccessCount > 25
| order by AccessCount desc
High-volume mailbox access
This hunt identifies users with unusually high mailbox read activity in a short window.
AuditLogs
| where Operation == "MailItemsAccessed"
| summarize AccessCount=count() by UserId, bin(TimeGenerated, 30m)
| where AccessCount > 100
| order by AccessCount desc
Login followed by inbox rule creation
This query looks for a successful sign-in followed by inbox rule creation within a short period.
let Signins =
SigninLogs
| where ResultType == 0
| project UserPrincipalName, SigninTime=TimeGenerated, IPAddress, AppDisplayName;
let Rules =
AuditLogs
| where Operation in ("New-InboxRule", "Set-InboxRule", "UpdateInboxRules")
| project UserId, RuleTime=TimeGenerated, Operation, ClientInfoString;
Signins
| join kind=inner Rules on $left.UserPrincipalName == $right.UserId
| where RuleTime between (SigninTime .. SigninTime + 30m)
| project UserPrincipalName, IPAddress, AppDisplayName, Operation, SigninTime, RuleTime, ClientInfoString
| order by RuleTime desc
MFA success followed by mailbox activity
AitM scenarios can include successful MFA. The concern is what happens immediately after the login.
let MfaSignins =
SigninLogs
| where ResultType == 0
| where AuthenticationRequirement =~ "multiFactorAuthentication"
| project UserPrincipalName, SigninTime=TimeGenerated, IPAddress, AppDisplayName;
let MailboxAccess =
AuditLogs
| where Operation == "MailItemsAccessed"
| project UserId, MailboxTime=TimeGenerated, ClientInfoString;
MfaSignins
| join kind=inner MailboxAccess on $left.UserPrincipalName == $right.UserId
| where MailboxTime between (SigninTime .. SigninTime + 60m)
| summarize MailboxEvents=count(), Clients=make_set(ClientInfoString), IPs=make_set(IPAddress)
by UserPrincipalName, bin(SigninTime, 1h)
| where MailboxEvents > 50
| order by MailboxEvents desc
What to check next
After a mailbox access anomaly, pivot into:
- Recent sign-ins and IP reputation
- Authentication method and MFA context
- Inbox rule creation or modification
- MailItemsAccessed volume and timing
- ClientInfoString and app/client changes
Containment mindset
When the pattern looks suspicious, prioritize:
- Revoke sessions
- Reset credentials
- Remove malicious inbox rules
- Review mailbox forwarding
- Confirm whether sensitive data was accessed
Detection is correlation
Bad activity rarely appears as one perfect alert. It shows up as a chain of behaviors: identity anomalies, suspicious client access, mailbox reads, and post-compromise changes.