Skip to content

Mailbox Rules & Hidden Inbox Manipulation as Persistence

In Business Email Compromise (BEC) and cloud intrusion campaigns, Exchange Online Inbox Rules represent the single most prevalent post-compromise mechanism deployed by adversaries. Once inside a victimโ€™s mailbox, the attackerโ€™s primary objectives are defense evasion (silencing security alerts, banking notifications, and victim inquiries) and automated exfiltration (forwarding sensitive financial discussions to external drop boxes).

While standard inbox rules are easily configured via Outlook Web App (OWA) or Outlook Desktop, sophisticated adversaries employ advanced techniquesโ€”including deceptive punctuation naming (".", "..", " ") and hidden MAPI rule corruptionโ€”to render these persistence hooks completely invisible within corporate email clients.

This guide provides an exhaustive technical dissection of inbox rule mechanics in Exchange Online, analyzes the hidden MAPI rule anomaly, decodes Purview Unified Audit Log telemetry, and provides production-grade KQL hunting queries and PowerShell extraction scripts.


In Exchange Online, inbox rules operate within the Exchange Store Driver pipeline:

graph TD
INCOMING[Inbound Email Traverses EOP Transport] --> STORE[Exchange Store Driver Delivery]
STORE --> RULES_EVAL{Inbox Rules Evaluator}
RULES_EVAL -->|Condition: Subject contains 'invoice / wire'| ACT_FWD[Action: ForwardTo / RedirectTo<br/>Dispatches copy to external attacker drop box]
RULES_EVAL -->|Condition: From security / IT / bank| ACT_DEL[Action: DeleteMessage / MoveToFolder<br/>Moves to \RSS Subscriptions or \Deletions]
RULES_EVAL -->|Default Rule Action| ACT_INBOX[Deposit in \Inbox]
ACT_FWD --> EXFIL[(External Drop Box)]
ACT_DEL --> BLIND[Victim Never Sees Notification]
ACT_INBOX --> USER_SEES[Normal User Experience]
  • Server-Side Rules: Executed autonomously by the Exchange Online Store Driver as soon as a message arrives, regardless of whether the user is logged in, running Outlook, or offline. All forwarding, redirection, and server folder move actions operate server-side.
  • Client-Only Rules: Depend on local Outlook Desktop execution (e.g., rules triggering desktop sounds or local print jobs). Threat actors almost exclusively deploy server-side rules.

Adversaries inject rules tailored to accomplish two synchronized objectives:

  1. Defense Evasion (Hiding the Intrusion):
    • Moving emails from IT security, banking portals, or vendor inquiries into obscure folders: \Archive, \Junk Email, \Conversation History, or \RSS Subscriptions.
    • Marking the email as read (MarkAsRead = $true) and deleting it immediately (DeleteMessage = $true).
  2. Automated Exfiltration:
    • Setting ForwardTo or RedirectTo to an external address (e.g., attacker@proton.me, finance-review@adversary-domain.com) for all messages matching financial keywords (invoice, wire, payment, statement, audit, ACH, SWIFT).

2. Stealth Techniques: Deceptive Naming & โ€œHiddenโ€ MAPI Rules

Section titled โ€œ2. Stealth Techniques: Deceptive Naming & โ€œHiddenโ€ MAPI Rulesโ€

To prevent the legitimate user from discovering the rule when opening Outlook settings, threat actors employ specific obfuscation techniques:

graph TD
TECH[Adversary Inbox Rule Obfuscation] --> T1[Technique 1: Deceptive / Whitespace Naming<br/>Names: '.', '..', ' ', 'None', 'Auto-Archive']
TECH --> T2[Technique 2: Subfolder Camouflage<br/>Target: \RSS Subscriptions, \Sync Issues, \Trash]
TECH --> T3[Technique 3: Hidden MAPI Rules<br/>Injected via EWS/MAPI bypassing OWA UI display]

Attackers frequently name rules using single punctuation marks or empty whitespace strings:

  • Rule Name: .
  • Rule Name: (single space)
  • Rule Name: ..
  • Rule Name: CleanUp

In the Outlook GUI, a rule named . appears as an empty line or insignificant dot, frequently dismissed by users during casual inspection.

A particularly insidious technique involves injecting rules directly via Messaging Application Programming Interface (MAPI) or Exchange Web Services (EWS) rather than OWA:

  1. Associated Contents Table Injection:
    • Inbox rules are stored as hidden FAI (Folder Associated Information) items in the Inbox folderโ€™s Associated Contents table.
  2. UI Rendering Failure:
    • If an attacker crafts a rule where standard MAPI properties (such as PR_RULE_NAME or PR_RULE_PROVIDER) are intentionally corrupted, omitted, or modified with unexpected types, the Outlook Web App and Outlook Desktop GUI fail to parse and display the rule.
    • When the user opens the โ€œRulesโ€ menu in OWA, the portal either displays an empty rules list or presents a generic error: โ€œThere was an error loading your rulesโ€.
  3. Execution Continuity:
    • Despite being invisible in the graphical user interface, the Exchange Store Driver continues to parse and execute the ruleโ€™s actions on every inbound email!

3. Forensic Telemetry in the Purview Unified Audit Log (UAL)

Section titled โ€œ3. Forensic Telemetry in the Purview Unified Audit Log (UAL)โ€

Every creation or modification of an inbox rule generates an audit record in the Purview Unified Audit Log:

  • RecordType: ExchangeItem (50) or ExchangeAdmin (2)
  • Operations: New-InboxRule, Set-InboxRule, UpdateInboxRules
// Example: Raw AuditData JSON from UAL for New-InboxRule
{
"CreationTime": "2026-03-24T09:12:45",
"Id": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"Operation": "New-InboxRule",
"OrganizationId": "8f3b6a9c-2d1e-4b5a-9f8e-7c6b5a4d3e2f",
"RecordType": 1,
"ResultStatus": "True",
"UserKey": "victim@target.com",
"UserType": 0,
"Workload": "Exchange",
"ClientIP": "198.51.100.22",
"UserId": "victim@target.com",
"MailboxOwnerUPN": "victim@target.com",
"ClientInfoString": "Client=REST;Client=OWA;Action=ViaProxy",
"Parameters": [
{ "Name": "Name", "Value": "." },
{ "Name": "Mailbox", "Value": "victim@target.com" },
{ "Name": "SubjectContainsWords", "Value": "invoice;wire;bank;payment;transfer" },
{ "Name": "ForwardTo", "Value": "external-drop@attacker-domain.com" },
{ "Name": "MarkAsRead", "Value": "True" },
{ "Name": "DeleteMessage", "Value": "True" }
]
}

Key forensic attributes:

  • Parameters[Name]: Detects deceptive names (".").
  • Parameters[ForwardTo] / Parameters[RedirectTo]: Captures the threat actorโ€™s external exfiltration address.
  • Parameters[DeleteMessage]: Proves intentional anti-forensics / defense evasion.
  • ClientIP: Maps directly back to the adversaryโ€™s proxy or session replay infrastructure.

4.1 Hunting Suspicious Inbox Rules (External Forwarding or Deletion)

Section titled โ€œ4.1 Hunting Suspicious Inbox Rules (External Forwarding or Deletion)โ€

Detect newly created or updated inbox rules that redirect mail externally or automatically delete messages:

CloudAppEvents
| where TimeGenerated >= ago(14d)
| where ActionType in ("New-InboxRule", "Set-InboxRule")
| extend Raw = parse_json(RawEventData)
| extend Parameters = Raw.Parameters
| mv-expand Parameters
| extend ParamName = tostring(Parameters.Name), ParamValue = tostring(Parameters.Value)
| summarize
RuleParams = make_bag(pack(ParamName, ParamValue)),
ClientIP = take_any(tostring(Raw.ClientIP)),
ClientApp = take_any(tostring(Raw.ClientInfoString))
by TimeGenerated, AccountDisplayName, ActionType
| extend RuleName = tostring(RuleParams.Name),
ForwardTo = tostring(RuleParams.ForwardTo),
RedirectTo = tostring(RuleParams.RedirectTo),
DeleteMessage = tostring(RuleParams.DeleteMessage),
MoveToFolder = tostring(RuleParams.MoveToFolder),
Keywords = tostring(RuleParams.SubjectContainsWords)
| where isnotempty(ForwardTo) or isnotempty(RedirectTo) or DeleteMessage == "True" or RuleName in (".", "..", " ", "None")
| project TimeGenerated, AccountDisplayName, ActionType, RuleName, ForwardTo, RedirectTo, DeleteMessage, MoveToFolder, Keywords, ClientIP
| sort by TimeGenerated desc

Identify inbox rules created within 2 hours of a suspicious sign-in event from a foreign location:

let SuspiciousSignins = SigninLogs
| where TimeGenerated >= ago(7d)
| where ResultType == 0
| where NetworkLocationDetails has "Unknown" or RiskLevelDuringSignIn in ("high", "medium")
| project SigninTime=TimeGenerated, UserPrincipalName, SigninIP=IPAddress, SigninLocation=Location;
CloudAppEvents
| where TimeGenerated >= ago(7d)
| where ActionType in ("New-InboxRule", "Set-InboxRule")
| extend ClientIP = tostring(parse_json(RawEventData).ClientIP)
| join kind=inner (SuspiciousSignins) on $left.AccountDisplayName == $right.UserPrincipalName
| where TimeGenerated between (SigninTime .. (SigninTime + 2h))
| project TimeGenerated, AccountDisplayName, ActionType, ClientIP, SigninIP, SigninLocation, RawEventData
| sort by TimeGenerated desc

Extract and analyze all active inbox rules across every mailbox in the organization:

Terminal window
# Connect to Exchange Online
# Connect-ExchangeOnline
Write-Host "[*] Auditing all mailbox inbox rules across tenant..." -ForegroundColor Cyan
$mailboxes = Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox
$suspiciousRules = @()
foreach ($mbx in $mailboxes) {
try {
$rules = Get-InboxRule -Mailbox $mbx.UserPrincipalName -ErrorAction Stop
foreach ($rule in $rules) {
# Flag rules that forward externally, delete messages, or use deceptive names
$isSuspicious = $false
if ($rule.ForwardTo -or $rule.RedirectTo -or $rule.DeleteMessage) {
$isSuspicious = $true
}
if ($rule.Name -match "^[\s\.]+$") {
$isSuspicious = $true
}
if ($isSuspicious) {
$suspiciousRules += [PSCustomObject]@{
Mailbox = $mbx.UserPrincipalName
RuleName = $rule.Name
Enabled = $rule.Enabled
Priority = $rule.Priority
ForwardTo = ($rule.ForwardTo -join "; ")
RedirectTo = ($rule.RedirectTo -join "; ")
DeleteMessage = $rule.DeleteMessage
MoveToFolder = $rule.MoveToFolder
SubjectContains= ($rule.SubjectOrBodyContainsWords -join "; ")
}
}
}
}
catch {
Write-Warning "Could not inspect rules for: $($mbx.UserPrincipalName) (Possible MAPI corruption)"
}
}
# Export findings
$suspiciousRules | Export-Csv -Path "C:\DFIR\Suspicious_Inbox_Rules.csv" -NoTypeInformation
Write-Host "[+] Audit complete. Found $($suspiciousRules.Count) suspicious inbox rules." -ForegroundColor Green
$suspiciousRules | Format-Table Mailbox, RuleName, ForwardTo, DeleteMessage
Terminal window
# Remove a malicious rule directly from the affected mailbox
$victim = "victim@target.com"
$maliciousRuleName = "."
# Locate and remove
$targetRule = Get-InboxRule -Mailbox $victim | Where-Object { $_.Name -eq $maliciousRuleName }
if ($targetRule) {
Remove-InboxRule -Mailbox $victim -Identity $targetRule.Identity -Confirm:$false
Write-Host "[+] Successfully removed malicious rule '$maliciousRuleName' from $victim" -ForegroundColor Green
}