Security researchers have identified a widespread campaign in which threat actors are attempting to access corporate Microsoft 365 environments using stolen session tokens — a technique being referred to as "token spraying." The campaign is directly linked to business email compromise (BEC) operations: attackers combine social engineering (typically adversary-in-the-middle phishing pages) with replayed authentication tokens to access mailboxes without ever needing a password — and, critically, without triggering MFA.
This is the mature, industrialized version of a technique we've watched evolve over the past two years. AiTM phishing kits (Evilginx-class proxies) harvest the session cookie after a victim completes legitimate authentication — including MFA. The attacker then replays that token from their own infrastructure, and Entra ID treats them as the authenticated user. At campaign scale, operators validate and "spray" large volumes of harvested tokens against M365 services (Exchange Online, SharePoint, Teams) to identify live sessions worth monetizing for BEC: invoice fraud, payroll diversion, and internal phishing pivots.
The defensive stakes are straightforward: if your detection strategy is anchored to password attacks (password spray, brute force) and MFA-prompt anomalies, you are blind to this technique. The authentication is legitimate. The MFA is satisfied. The only signal is context — where the token is used from, on what device, and what the session does next.
Technical Analysis
Affected Platform
- Microsoft 365 / Entra ID — Exchange Online, SharePoint Online, OneDrive, Teams, and the Graph API
- Any tenant where Conditional Access is not enforcing token protection, compliant-device requirements, or sign-in risk policies
No CVE is associated with this campaign. This is not a software vulnerability — it is abuse of legitimate authentication architecture. The session token is working exactly as designed; the problem is that its bearer is not the legitimate user.
Attack Chain
- Lure delivery. Victims receive a phishing email (often a threaded reply-chain hijack from an already-compromised partner account) with a link to a credential-harvesting page.
- AiTM proxy interception. The phishing kit proxies the real Microsoft login flow. The victim enters credentials and completes MFA. The proxy captures the resulting session token/cookie in transit.
- Token validation and spraying. Operators replay harvested tokens in bulk against M365 endpoints to identify valid, unexpired sessions — hence "token spraying."
- Mailbox access and BEC staging. Valid sessions are used to read mail, establish persistence (inbox rules that hide replies, mail forwarding, OAuth consent grants), and reconnoiter payment workflows.
- Monetization. Invoice redirection, payroll changes, W-2 harvesting, or internal phishing to expand the token pool.
Exploitation Status
Confirmed active, widespread, in-the-wild exploitation. This is not theoretical. BEC remains the highest-financial-impact cybercrime category by a wide margin, and token-replay has become the default access method for these crews precisely because it defeats password-based and MFA-based defenses. There is no CISA KEV entry because there is no patchable flaw — remediation is architectural.
Why Traditional Controls Fail
- MFA (push/SMS/TOTP): Satisfied by the real user during the AiTM flow. The token inherits the satisfied claim.
- Password hygiene / rotation: Irrelevant — the attacker never uses the password again.
- Failed-login alerting: Token replay produces successful sign-ins.
The controls that matter are phishing-resistant MFA (FIDO2/passkeys, certificate-based auth), token binding (Conditional Access token protection), and contextual anomaly detection on session use.
Detection & Response
The detections below target the observable seams in this attack: anomalous session-token use in sign-in logs, BEC staging behaviors (inbox rules, forwarding, OAuth consent), and endpoint-side token theft artifacts.
Sigma Rules
---
title: Suspicious Inbox Rule Creation Indicating BEC Staging
id: 3f8c2a91-7b4d-4e19-a6c2-9d1e5f7b3a08
status: experimental
description: Detects creation of inbox rules that hide or redirect mail, a hallmark of post-compromise BEC staging in Microsoft 365 token-theft campaigns.
references:
- https://attack.mitre.org/techniques/T1098/002/
- https://www.infosecurity-magazine.com/news/tokenspraying-attacks-target/
author: Security Arsenal
date: 2026/01/15
tags:
- attack.persistence
- attack.collection
- attack.t1098.002
- attack.t1114.003
logsource:
product: office365
service: exchange
detection:
selection_operation:
Operation:
- 'New-InboxRule'
- 'Set-InboxRule'
selection_hide:
Parameters|contains:
- 'DeleteMessage'
- 'MoveToFolder'
- 'MarkAsRead'
- 'ForwardTo'
- 'RedirectTo'
filter_folder:
Parameters|contains:
- 'RSS Feeds'
- 'Conversation History'
- 'Archive'
- 'Junk'
condition: selection_operation and selection_hide and not filter_folder
falsepositives:
- Legitimate user-created organization rules (tune per tenant baseline)
level: high
---
title: OAuth Consent Grant to Unverified Application Following Sign-In
id: 8b2e4d17-3c6a-4f85-b1d9-2e7a6c4f9d52
status: experimental
description: Detects consent grants to applications requesting mail-access scopes, a common persistence mechanism after session-token compromise in M365 BEC campaigns.
references:
- https://attack.mitre.org/techniques/T1550/001/
- https://attack.mitre.org/techniques/T1528/
author: Security Arsenal
date: 2026/01/15
tags:
- attack.persistence
- attack.t1550.001
- attack.credential_access
logsource:
product: azure
service: auditlogs
detection:
selection:
operationName:
- 'Consent to application'
- 'Add service principal credentials'
- 'Add app role assignment to service principal'
selection_scope:
targetResources|contains:
- 'Mail.Read'
- 'Mail.ReadWrite'
- 'Mail.Send'
- 'offline_access'
- 'full_access_as_app'
condition: selection and selection_scope
falsepositives:
- Approved third-party mail integrations (maintain an allowlist of publisher-verified apps)
level: high
---
title: Session Token Replay From Anomalous Client Context
id: 5a1d9f36-2e8b-4c47-93a6-7f4b2e8d1c63
status: experimental
description: Detects successful Entra ID sign-ins using previously satisfied authentication claims from unmanaged devices, consistent with replayed session tokens bypassing interactive MFA.
references:
- https://attack.mitre.org/techniques/T1550/001/
author: Security Arsenal
date: 2026/01/15
tags:
- attack.initial_access
- attack.t1550.001
- attack.t1078
logsource:
product: azure
service: signinlogs
detection:
selection:
status.errorCode: 0
selection_token:
authenticationDetails|contains:
- 'Previously satisfied'
- 'Token protection - not satisfied'
selection_device:
deviceDetail.trustType:
- ''
- null
condition: selection and selection_token and selection_device
falsepositives:
- Legitimate BYOD access where device enrollment is not enforced
- Cached sessions on unmanaged home devices
level: medium
Analyst note on rule three: This is your highest-fidelity token-replay signal but requires tuning. Establish a baseline of users' normal device trust states first. In tenants enforcing compliant-device CA policies, this rule becomes close to surgical; in permissive tenants, scope it to sensitive users (finance, executives, AP/AR) before broad deployment.
KQL — Microsoft Sentinel / Defender Hunt
This hunt correlates successful sign-ins that reused previously satisfied authentication (token replay indicator) with impossible-travel velocity and known BEC staging activity in the same window:
// Token-replay hunt: previously-satisfied auth + impossible travel + BEC staging
let lookback = 14d;
let travel_window = 3h;
let ReplaySignins =
SigninLogs
| where TimeGenerated > ago(lookback)
| where ResultType == 0
| extend AuthDetail = tostring(AuthenticationDetails)
| where AuthDetail has "Previously satisfied"
or tostring(ConditionalAccessPolicies) has "token protection"
| extend Location = tostring(LocationDetails)
| project TimeGenerated, UserPrincipalName, IPAddress, Location,
AppDisplayName, DeviceDetail, CorrelationId;
let ImpossibleTravel =
ReplaySignins
| sort by UserPrincipalName, TimeGenerated asc
| serialize
| extend PrevLocation = prev(Location), PrevTime = prev(TimeGenerated),
PrevIP = prev(IPAddress)
| where UserPrincipalName == prev(UserPrincipalName)
| where Location != PrevLocation
and datetime_diff('minute', TimeGenerated, PrevTime) < 180
| project ReplayTime=TimeGenerated, UserPrincipalName, ReplayIP=IPAddress,
ReplayLocation=Location, PriorLocation=PrevLocation, PriorIP=PrevIP;
ImpossibleTravel
| join kind=leftouter (
OfficeActivity
| where TimeGenerated > ago(lookback)
| where Operation in~ ("New-InboxRule","Set-InboxRule","Set-Mailbox",
"Add-MailboxPermission","Consent to application")
| extend UPN = tostring(UserId)
| project StageTime=TimeGenerated, UPN, Operation,
Params=tostring(Parameters), ClientIP
) on $left.UserPrincipalName == $right.UPN
| where isempty(StageTime) or abs(datetime_diff('hour', StageTime, ReplayTime)) < 24
| project ReplayTime, UserPrincipalName, ReplayIP, ReplayLocation,
PriorLocation, PriorIP, StageTime, Operation, ClientIP
| order by UserPrincipalName asc
A companion quick-triage query for SOC analysts — external forwarding configured on mailboxes, the single most common BEC monetization artifact:
// Mailbox forwarding configured to external domains (BEC monetization artifact)
OfficeActivity
| where TimeGenerated > ago(7d)
| where Operation =~ "Set-Mailbox"
| extend Params = tostring(Parameters)
| where Params has_any ("ForwardingSmtpAddress","ForwardingAddress")
and Params !has ""
| mv-apply Param = parse_json(Params) on (
where Param.Name in ("ForwardingSmtpAddress","ForwardingAddress")
| extend ForwardTarget = tostring(Param.Value)
)
| where isnotempty(ForwardTarget)
| extend TargetDomain = tostring(split(ForwardTarget, "@")[1])
| where TargetDomain !in~ ("yourdomain.com","yourtenant.onmicrosoft.com")
| project TimeGenerated, UserId, ForwardTarget, ClientIP, Operation
Velociraptor VQL — Endpoint Token-Theft Hunt
Token spraying campaigns feed on bulk token theft, much of it originating from commodity infostealers ripping browser session stores. This artifact hunts for suspicious processes running from user-writable locations that reference browser credential artifacts, plus recently dropped executables in common staging paths:
-- Hunt for infostealer-style access to browser session/token stores
-- and recently staged executables feeding M365 token theft
LET suspicious_procs = SELECT Pid, Ppid, Name, Exe, CommandLine, Username,
CreateTime
FROM pslist()
WHERE (Exe =~ '(?i)\\(Temp|AppData\\Local\\Temp|Downloads|ProgramData)\\[^\\]+\.exe$'
AND CommandLine =~ '(?i)(Login Data|Cookies|Local State|chrome|edge|token|cookie)')
OR Name =~ '(?i)(redline|vidar|raccoon|stealc|lumma|agenttesla)'
LET staged_files = SELECT FullPath, Size, Mtime, Ctime
FROM glob(globs='C:\\Users\\*\\AppData\\Local\\Temp\\*.exe',
accessor='ntfs')
WHERE Mtime > Now() - 604800
SELECT * FROM suspicious_procs
UNION ALL
SELECT NULL AS Pid, NULL AS Ppid, 'STAGED_FILE' AS Name, FullPath AS Exe,
'' AS CommandLine, '' AS Username, Mtime AS CreateTime
FROM staged_files
Deploy this as a hunt across finance and executive endpoints first — those are the accounts with BEC monetization value.
Remediation / Hardening Script
The following PowerShell uses the Microsoft Graph SDK to revoke active sessions for a compromised user, enumerate suspicious OAuth grants, and audit mailbox forwarding. Run with an account holding User.ReadWrite.All, Application.Read.All, and Directory.Read.All (or Exchange Online for the mailbox portion):
# Token-theft IR: session revocation, OAuth grant audit, forwarding check
# Requires: Microsoft.Graph SDK (Install-Module Microsoft.Graph)
param(
[Parameter(Mandatory=$true)]
[string]$CompromisedUPN
)
Connect-MgGraph -Scopes "User.ReadWrite.All","Application.Read.All","Directory.Read.All","AuditLog.Read.All"
# STEP 1: Immediately invalidate all refresh tokens and session cookies
$user = Get-MgUser -UserId $CompromisedUPN
Revoke-MgUserSignInSession -UserId $user.Id
Write-Host "[+] Sessions revoked for $CompromisedUPN — all stolen tokens are now dead." -ForegroundColor Green
# STEP 2: Audit OAuth consent grants for mail-access scopes (persistence check)
$grants = Get-MgUserOAuth2PermissionGrant -UserId $user.Id -All
$suspicious = $grants | Where-Object { $_.Scope -match "Mail\.|offline_access|full_access" }
if ($suspicious) {
Write-Host "[!] Suspicious consent grants found — remove attacker persistence:" -ForegroundColor Red
$suspicious | Format-Table ClientId, Scope, ConsentType
# Remove after validation: Remove-MgOAuth2PermissionGrant -OAuth2PermissionGrantId <id>
}
# STEP 3: Check for credential changes (app passwords / new auth methods added post-compromise)
Get-MgAuditLogDirectoryAudit -Filter "targetResources/any(t: t/id eq '$($user.Id)')" -Top 50 |
Where-Object { $_.ActivityDisplayName -match "credential|password|authentication" } |
Format-Table ActivityDateTime, ActivityDisplayName, InitiatedBy
# STEP 4 (Exchange Online): hunt BEC staging — forwarding + hiding rules
Connect-ExchangeOnline
$forwarding = Get-Mailbox -Identity $CompromisedUPN |
Select-Object ForwardingAddress, ForwardingSmtpAddress
if ($forwarding.ForwardingSmtpAddress -or $forwarding.ForwardingAddress) {
Write-Host "[!] MAIL FORWARDING CONFIGURED: $CompromisedUPN" -ForegroundColor Red
$forwarding | Format-List
}
Get-InboxRule -Mailbox $CompromisedUPN |
Where-Object { $_.DeleteMessage -or $_.ForwardTo -or $_.RedirectTo -or
$_.MoveToFolder -match "RSS|Archive|Conversation History" } |
Format-Table Name, DeleteMessage, ForwardTo, RedirectTo, MoveToFolder
# STEP 5: Force password reset as defense-in-depth (token is dead, but credential is burned)
$pwdProfile = @{ Password = (New-Guid).ToString() + "!aZ9"; ForceChangePasswordNextSignIn = $true }
Update-MgUser -UserId $user.Id -PasswordProfile $pwdProfile
Write-Host "[+] Password randomized. Coordinate out-of-band reset with the user." -ForegroundColor Green
Remediation & Hardening
There is no patch. The fix is architectural, and every one of these is deployable today:
- Deploy phishing-resistant MFA. FIDO2 security keys, passkeys, or Windows Hello for Business. AiTM proxies cannot relay origin-bound, hardware-backed authentication. Prioritize finance, payroll, executives, and helpdesk staff.
- Enable Conditional Access token protection (sign-in session binding). Available in Entra ID P1/P2 — it cryptographically binds tokens to the issuing device, making replayed tokens from attacker infrastructure worthless. This is the single most direct counter to token spraying.
- Require compliant or hybrid-joined devices for M365 access. Stolen tokens replayed from attacker VPS infrastructure fail device-conditional evaluation.
- Enable Entra ID Protection sign-in risk policies with automated remediation (block or force re-authentication on anomalous token use, unfamiliar sign-in properties, and impossible travel).
- Restrict user consent for applications (admin consent workflow only) and audit existing grants for mail scopes. OAuth persistence survives session revocation if not removed.
- Block legacy authentication (IMAP/POP/basic auth) tenant-wide and disable external auto-forwarding in Exchange transport rules.
- Shorten token lifetimes via Conditional Access sign-in frequency policies for high-risk roles — shrinks the window in which a stolen token is useful.
- On confirmed compromise: revoke sessions immediately (script above), remove OAuth grants and inbox rules, reset credentials, review 30 days of mail flow and SharePoint access for the account, and notify counterparties who may have received fraudulent payment instructions.
The detection window on these campaigns is everything. BEC crews move from token replay to fraudulent wire instruction in hours, not days. If your SOC is not alerting on previously-satisfied authentication from unmanaged devices and on inbox-rule creation, you are flying blind against the most financially destructive attack class in the threat landscape.
Related Resources
Security Arsenal Incident Response Services AlertMonitor Platform Book a SOC Assessment incident-response Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.