Business Email Compromise Playbook
Detecting inbox rule manipulation, OAuth app abuse, mail forwarding persistence, and fraudulent wire transfer — and the 72-hour window to recover stolen funds.
Your CFO's assistant calls the SOC: the CFO's email account was used to approve a $340,000 wire transfer yesterday. The CFO says they didn't approve it. In BEC incidents, time is the adversary: the FBI's financial fraud unit has a 72-hour window to place a "financial freeze" on fraudulent wire transfers before the money is moved to overseas accounts. Every hour you spend figuring out what happened is an hour of recovery time lost. This playbook handles both tracks simultaneously: the fraud recovery track and the technical containment track.
The Two Simultaneous Tracks
BEC Response: Parallel Tracks
═══════════════════════════════════════════════════════════════════
TRACK 1: FINANCIAL FRAUD RECOVERY (time-critical)
─────────────────────────────────────────────────
T+0:00 Confirm fraudulent transfer with Finance
T+0:30 Call your bank's fraud department — request wire recall
T+1:00 File FBI IC3 complaint at ic3.gov
T+2:00 Call FBI local field office financial crimes unit
(not just the IC3 website — direct call speeds freeze request)
T+24h 72-hour window — any freeze must be in place by this point
The FBI can file SWIFT network alerts and coordinate with
destination bank to freeze funds
TRACK 2: TECHNICAL INVESTIGATION AND CONTAINMENT
─────────────────────────────────────────────────
T+0:00 Disable compromised account (if confirmed)
T+0:30 Revoke all OAuth tokens and active sessions
T+1:00 Audit inbox rules — find any forwarding rules
T+2:00 Audit OAuth app consents — find any attacker-registered apps
T+4:00 Full mailbox audit — what was accessed, forwarded, deleted?
T+6:00 Scope expansion — are other accounts affected?
Mailbox Forensics
# Exchange Online / O365 BEC Investigation
# Requires ExchangeOnlineManagement module and audit logs enabled
Connect-ExchangeOnline
$victimUPN = "jsmith@corp.com"
# 1. Check for inbox rules — attackers create rules to forward emails to external accounts
# or delete specific alerts (security alerts, finance notifications)
Get-InboxRule -Mailbox $victimUPN | Select-Object Name, Description,
ForwardTo, ForwardAsAttachmentTo, RedirectTo, DeleteMessage, Enabled |
Format-List
# 2. Look at recently modified/created inbox rules
Get-InboxRule -Mailbox $victimUPN -IncludeHidden | Format-List *
# 3. Check OAuth app consents for this user
# (via Azure AD portal or Graph API)
# az ad app list --filter "appId eq 'specific-app-id'" or review Entra ID → Enterprise Apps
# 4. Audit log: what was accessed?
# (Requires Unified Audit Log enabled and E3/E5 license for full detail)
$endDate = Get-Date
$startDate = $endDate.AddDays(-30)
Search-UnifiedAuditLog -StartDate $startDate -EndDate $endDate `
-UserIds $victimUPN -RecordType ExchangeItem `
-ResultSize 1000 | Where-Object {
$_.Operations -in @("MailItemsAccessed","MessageBind","Create","Update","MoveToDeletedItems")
} | Select-Object CreationDate, Operations, ClientIP, AuditData |
Sort-Object CreationDate | Format-Table
# Azure AD sign-in logs for the compromised account
# Look for: suspicious IPs, impossible travel, unfamiliar device/browser
Connect-MgGraph -Scopes "AuditLog.Read.All"
$filter = "userPrincipalName eq 'jsmith@corp.com' and createdDateTime gt 2026-08-01T00:00:00Z"
Get-MgAuditLogSignIn -Filter $filter -Top 200 |
Select-Object CreatedDateTime, IpAddress, Location, ClientAppUsed,
IsInteractive, ConditionalAccessStatus,
@{N="Status"; E={ $_.Status.ErrorCode }} |
Sort-Object CreatedDateTime |
Format-Table
# Red flags in output:
# - IPs from unexpected countries
# - Non-interactive sign-ins (refresh token reuse) after password reset
# - ClientAppUsed = "Other clients" or "IMAP4" (legacy auth, bypasses MFA)
# - IsInteractive = False (OAuth token replay — doesn't require new MFA)
BEC Indicators of Compromise
| Indicator | What it means | Where to find it |
|---|---|---|
| Inbox rule forwarding to external address | Attacker is receiving a copy of all incoming email | Get-InboxRule output |
| Inbox rule deleting specific subjects | Attacker deleting security alerts or fraud notifications to avoid victim noticing | Get-InboxRule — DeleteMessage=True |
| OAuth app granted full mailbox access | Attacker registered an OAuth app with Mail.ReadWrite permission | Azure AD → Enterprise Apps → Permissions |
| Non-interactive sign-ins from new IP after MFA reset | Refresh token still alive despite password reset | Azure AD Sign-In logs |
| Legacy authentication protocol (IMAP/POP) | Attacker using legacy auth to bypass MFA — a persistent access method | Azure AD Sign-In logs: ClientAppUsed = IMAP/POP |
| Email sent from account at unusual hours | Attacker actively using the account to conduct fraud | Exchange mail sent items or audit log |
BEC Containment Steps
# BEC containment — in order
# 1. Disable the account immediately
Set-MgUser -UserId "jsmith@corp.com" -AccountEnabled $false
# 2. Revoke all active sessions and refresh tokens
Invoke-MgUserInvalidateAllRefreshToken -UserId "jsmith@corp.com"
# 3. Remove malicious inbox rules
Get-InboxRule -Mailbox "jsmith@corp.com" |
Where-Object { $_.ForwardTo -or $_.ForwardAsAttachmentTo -or $_.RedirectTo } |
ForEach-Object {
Write-Host "Removing rule: $($_.Name) — ForwardTo: $($_.ForwardTo)"
Remove-InboxRule -Mailbox "jsmith@corp.com" -Identity $_.RuleIdentity -Confirm:$false
}
# 4. Block legacy authentication (prevents IMAP/POP bypass of MFA)
# Via Conditional Access: Block legacy auth for all users, or this user specifically
# Via Azure AD → Security → Conditional Access → New Policy
# Conditions: Client Apps → Exchange ActiveSync + Other Clients
# Access Control: Block
# 5. Reset password and require MFA re-registration
Set-MgUserPassword -UserId "jsmith@corp.com" `
-PasswordProfile @{ Password = (New-Guid).ToString() + "Aa1!"; ForceChangePasswordNextSignIn = $true }
Q & A
Q: The wire transfer was sent to a domestic bank account. Does the 72-hour window still apply?
Yes — domestic wires can still be recalled. Call your bank's wire fraud department immediately, referencing the date, amount, and destination account. Request a "wire recall" (also called "return of funds"). For domestic transfers, the bank may be able to contact the receiving bank directly and freeze the funds if they haven't been moved. File an IC3 complaint as well — even for domestic fraud, FBI involvement can speed up the process with the receiving bank. Also: contact your cyber insurance carrier immediately — many policies cover BEC losses, and the insurer's panel may have relationships with fraud recovery specialists who work with banks directly.
Q: You remove the attacker's inbox forwarding rule, reset the password, and revoke tokens. The next morning, the attacker is still in the mailbox. How?
Three likely paths: (1) The attacker has a legitimate OAuth app consent that survived the token revocation — OAuth app permissions persist even after token revocation unless you also revoke the app consent. Check Azure AD → Enterprise Apps → [user] → Permissions and revoke any unfamiliar app consents. (2) The attacker created a hidden inbox rule that you didn't find — re-run Get-InboxRule with -IncludeHidden, and also check via REST API which sometimes shows rules the cmdlet doesn't. (3) Another account in the organization was also compromised and the attacker is now accessing the mailbox via a delegation or shared mailbox permission. Check mailbox permissions: Get-MailboxPermission -Identity "jsmith@corp.com".