Security & identity

Compromised Microsoft 365 account runbook: contain, investigate, recover

A step-by-step runbook for a confirmed Microsoft 365 account takeover: disable and revoke, remove attacker persistence, scope the breach with audit logs and restore the user safely.

13 min read
On this page

When a Microsoft 365 account is confirmed compromised, work in three phases: contain (disable the account, revoke its sessions and mark it compromised), remove persistence (rogue MFA methods, app consents, admin roles, mailbox forwarding and inbox rules), then investigate and recover (scope the activity with sign-in logs and Purview Audit, reset the password, re-enable with MFA and lift any sending block). Containment comes first because a password reset alone doesn't end existing sessions, and everything the attacker set up keeps working until you remove it.

Who this is for and what you will have

This runbook is for Microsoft 365 and security administrators who have a confirmed account takeover: a user reports a suspicious MFA prompt they approved, Defender raises an incident, or a partner reports a fraudulent payment request sent from your domain. It follows Microsoft's published order for compromised accounts and adds the commands you need at each step. At the end you will have:

  • The attacker locked out of Microsoft Entra ID and every app that relies on it.
  • Every known persistence mechanism reviewed and removed.
  • A timeline of what the attacker did, which mail they accessed and which files they touched, exported for your records.
  • The user back at work with a new password, clean MFA methods and their account marked accordingly in ID Protection.

The response order at a glance

PhaseActionToolLeast privileged role
ContainDisable the accountEntra admin center, Graph PowerShellUser Administrator (Privileged Authentication Administrator for admin accounts)
ContainRevoke sessionsEntra admin center, Graph PowerShellAuthentication Administrator or User Administrator
ContainConfirm or mark compromisedID Protection, Defender portalSecurity Operator
PersistenceReview MFA methods and app passwordsEntra admin center, Graph PowerShellAuthentication Administrator
PersistenceReview app consentsEntra admin center, Graph PowerShellCloud Application Administrator
PersistenceReview forwarding and inbox rulesExchange Online PowerShellExchange recipient management permissions
InvestigateSearch the audit logPurview portal, Exchange Online PowerShellAudit Logs or View-Only Audit Logs
RecoverReset password, re-enable, unblock sendingEntra admin center, Defender portalUser Administrator, Security Administrator

Keep a written log of each action, who took it and when; you will need it for the investigation timeline.

Prerequisites

  • Accounts holding the roles in the table above. If your tenant uses Privileged Identity Management, activate them before you start.
  • The Microsoft Graph PowerShell SDK (Microsoft.Graph.Users, Microsoft.Graph.Users.Actions, Microsoft.Graph.Identity.DirectoryManagement, Microsoft.Graph.Identity.SignIns, Microsoft.Graph.Applications) and the Exchange Online PowerShell module.
  • For hybrid identities, access to an on-premises Active Directory admin workstation.
  • For the Confirm compromised workflow and full risk reports, Microsoft Entra ID P2 or Microsoft Entra Suite. The rest of the runbook works without it.
  • Unified audit log ingestion turned on. Check it in Exchange Online PowerShell (not Security & Compliance PowerShell, where the property always shows False):
Get-AdminAuditLogConfig | Format-List UnifiedAuditLogIngestionEnabled

Phase 1: Contain the account

Step 1: Disable the user

Microsoft recommends disabling the compromised account until the investigation is complete. In the Microsoft Entra admin center, go to Entra ID > Users > All users, select the user, select Edit under Account status, clear Account enabled and select Save.

For repeatable or bulk response, use Microsoft Graph PowerShell:

Connect-MgGraph -Scopes "User.ReadWrite.All","Directory.AccessAsUser.All"
 
$User = Get-MgUser -Search UserPrincipalName:'jason@contoso.com' -ConsistencyLevel eventual
Update-MgUser -UserId $User.Id -AccountEnabled:$false

If the account is synchronized from on-premises Active Directory, Microsoft's guidance is to disable it there as well and reset the password twice, to reduce the risk of pass-the-hash while replication catches up. Use random values, not the placeholders below:

Disable-ADAccount -Identity jason
Set-ADAccountPassword -Identity jason -Reset -NewPassword (Read-Host -AsSecureString "First random password")
Set-ADAccountPassword -Identity jason -Reset -NewPassword (Read-Host -AsSecureString "Second random password")

If the identity is federated, change the password in the on-premises environment.

Step 2: Revoke sessions

Disabling the account blocks new sign-ins, but apps that already hold tokens keep working until those tokens are refused. Revoke the user's refresh tokens and sign-in sessions immediately. In the admin center, open the user's Overview page and select Revoke sessions. In PowerShell:

Connect-MgGraph -Scopes User.RevokeSessions.All
Revoke-MgUserSignInSession -UserId $User.Id

Understand what this does and doesn't cover:

  • Access tokens issued by Microsoft Entra ID last 1 hour by default. An app holding one can keep using it until it expires, unless the app supports continuous access evaluation (CAE), which lets revocation take effect in near real time.
  • Browser-based apps often issue their own session cookie after the Entra sign-in. Microsoft Entra ID can't revoke that cookie; the app ends the session when its own token expires or when it learns the account is disabled.

Step 3: Disable compromised devices

If the attacker registered or joined a device to the tenant under this user, or you believe one of the user's devices is compromised, disable the user's registered devices. This requires at least Cloud Device Administrator:

Get-MgUserRegisteredDevice -UserId $User.Id -All | ForEach-Object {
    Update-MgDevice -DeviceId $_.Id -AccountEnabled:$false
}

This disables every device registered to the user, including their legitimate laptop. Review the list first if you only want to disable the attacker's device.

Step 4: Mark the user as compromised

Marking the account tells ID Protection that the risk is real, which updates the risk state to Confirmed compromised and feeds the detection models. In the Microsoft Entra admin center, go to Protection > Identity Protection > Risky users, select the user and choose Confirm compromised. Security Operator is the least privileged role for this.

If you work from the Microsoft Defender portal, go to Assets > Identities, open the identity and use the Actions menu. Depending on the connectors you have, the actions are Disable, Enable, Revoke session, Mark as compromised and Force password change, and they apply across the accounts Defender correlates to that identity, including on-premises Active Directory when Defender for Identity sensors run on your domain controllers. Track progress under Actions & submissions > Action center.

Phase 2: Remove the attacker's persistence

An attacker who expects to lose the password plants other ways back in. Check each of the following before you re-enable the account.

MFA methods and app passwords

Attackers often register their own phone number or authenticator app. List every method registered to the user:

Connect-MgGraph -Scopes "UserAuthenticationMethod.ReadWrite.All"
Get-MgUserAuthenticationMethod -UserId jason@contoso.com |
    Select-Object Id, @{n='Type';e={$_.AdditionalProperties.'@odata.type'}}

In the Microsoft Entra admin center, as at least Authentication Administrator, go to Entra ID > Users, select the user and open Authentication methods. Delete anything the user doesn't recognize, or select Require re-register MFA, which deletes the user's phone numbers, Microsoft Authenticator registrations and software OATH tokens and deactivates hardware OATH tokens, so the user sets up fresh methods at next sign-in.

App passwords aren't revoked by a password reset. Under Entra ID > Users > Multifactor authentication, select the user, choose Manage user settings and check Delete all existing app passwords generated by the selected users.

Application consents

A malicious app that the user consented to keeps its delegated access after a password reset. List the user's delegated permission grants:

Connect-MgGraph -Scopes "Directory.Read.All","DelegatedPermissionGrant.ReadWrite.All"
Get-MgUserOauth2PermissionGrant -UserId $User.Id -All |
    Format-List ClientId, ConsentType, Scope

ClientId is the object ID of the app's service principal; look it up with Get-MgServicePrincipal -ServicePrincipalId <ClientId>. To remove a grant you don't trust, run Remove-MgOauth2PermissionGrant -OAuth2PermissionGrantId <Id> as at least Cloud Application Administrator. The portal can't revoke grants shown on an app's User consent tab, so use PowerShell or Graph for these. Revoking a grant doesn't stop the user from consenting again; restrict user consent tenant-wide if this was the entry point.

Admin roles

Review the user's Microsoft Entra role assignments, Azure role assignments, and Purview and Defender permissions. Remove any role the user shouldn't hold, and treat a recently added role as evidence: search the audit log for the Add member to role. operation (the trailing period is part of the name).

Mailbox forwarding, inbox rules and delegates

Connect to Exchange Online PowerShell and check SMTP forwarding and inbox rules, including hidden ones:

Get-Mailbox -Identity jason@contoso.com | Format-List Forwarding*Address,DeliverTo*
Get-InboxRule -Mailbox jason@contoso.com -IncludeHidden |
    Format-List Name,Enabled,RedirectTo,Forward*,Identity

A nonblank ForwardingSmtpAddress means mail is being forwarded to an external recipient. Look for rules that forward or redirect mail, or move messages into Notes, Junk Email or RSS Subscriptions where the user won't see replies. Remove what the attacker created with Remove-InboxRule and clear forwarding with Set-Mailbox. Also review Full Access and Send As permissions on the mailbox.

Phase 3: Investigate what happened

Start the evidence collection early. Audit (Standard) keeps records for 180 days; users with E5 or the Purview Suite or E5 eDiscovery and Audit add-on get one year for Microsoft Entra ID, Exchange and SharePoint records by default. Anything outside that window is gone.

Sign-in logs

In the Microsoft Entra sign-in logs, filter on the user from just before the first suspicious event and compare IP addresses, locations, times and success or failure. The attacker's IP addresses and the session IDs you find here become filters for every later search. In the Defender portal, the identity page's Timeline tab puts Entra sign-ins, Conditional Access results, Microsoft Graph activity, cloud app events and alerts for that identity on one timeline.

Unified audit log

In the Microsoft Purview portal, open the Audit solution and create a search for the user over the compromise window. Don't filter by activity on the first pass. Date ranges can be at most 180 days, searches keep running after you close the browser, and completed searches are kept for 30 days. Exports are limited to 50,000 rows for Audit (Standard) and 1,000,000 rows for Audit (Premium). Searching requires the Audit Logs or View-Only Audit Logs role.

To script it, use Search-UnifiedAuditLog in Exchange Online PowerShell. By default it returns up to 100 records; use -SessionCommand ReturnLargeSet with a fixed -SessionId and run the command repeatedly to page through up to 50,000 unsorted results:

$start = (Get-Date "2026-10-01 00:00").ToUniversalTime()
$end   = (Get-Date).ToUniversalTime()
$ops = "New-InboxRule","Set-InboxRule","UpdateInboxRules","Add-MailboxPermission",
       "Send","SendAs","HardDelete","SoftDelete","MoveToDeletedItems",
       "FileDownloaded","FileAccessed","Add delegation entry.","Add service principal.",
       "Reset user password.","Update user.","Add member to role."
 
$results = @()
do {
    $page = Search-UnifiedAuditLog -StartDate $start -EndDate $end `
        -UserIds jason@contoso.com -Operations $ops `
        -SessionId "IR-jason" -SessionCommand ReturnLargeSet -ResultSize 5000
    $results += $page
} while ($page)
 
$results | Export-Csv .\IR-jason-audit.csv -NoTypeInformation

Add -IPAddresses with the attacker's addresses to separate their activity from the user's. Exchange admin cmdlets such as Set-Mailbox are recorded under the ExchangeAdmin record type.

Which mail the attacker accessed

The MailItemsAccessed operation is enabled by default for users with Office 365 or Microsoft 365 E3 or E5 licenses and covers POP, IMAP, MAPI, EWS, Exchange ActiveSync and REST access. It records two kinds of access:

  • Sync: recorded only for desktop Outlook on Windows or Mac, one record per folder. If a sync record matches the attacker's IP address and client, assume every item in that folder, and potentially the whole mailbox, was downloaded.
  • Bind: access to individual messages, aggregated into one record per 2-minute interval, with each message identified by its InternetMessageId.
Search-UnifiedAuditLog -StartDate $start -EndDate $end -UserIds jason@contoso.com `
    -Operations MailItemsAccessed -ResultSize 5000 |
    Where-Object { $_.AuditData -like '*"MailAccessType","Value":"Bind"*' }

Compare ClientIPAddress, ClientInfoString and SessionId in AuditData against the attacker activity you found in the sign-in logs. The message IDs from bind records tell you exactly which messages to review for sensitive data.

What the attacker sent

Use message trace in the Defender portal for the compromise window and check Sent Items and Deleted Items. Fraudulent payment requests, internal phishing and mass outbound spam all show up here, and internal recipients of phishing from this account need their own follow-up.

Phase 4: Recover the account

When the investigation is complete and every persistence mechanism is gone:

  1. Reset the password to a strong, unique value. Don't reuse any of the last five passwords, and don't send the new password by email: the attacker may still have a copy of the mailbox. For hybrid users, reset it in Active Directory.
  2. Re-enable the account (Account enabled in the user's properties, or Update-MgUser -UserId $User.Id -AccountEnabled:$true).
  3. Have the user register fresh MFA methods, ideally phishing-resistant ones, and make sure a Conditional Access policy requires MFA for them. For the wider pattern of verifying every request instead of trusting the network, see Zero Trust remote access architecture.
  4. If the mailbox was used to send spam, it's probably on the Restricted entities page in the Defender portal. Remove it there so the user can send again.
  5. Re-enable any devices you disabled after they've been reimaged or confirmed clean.

Verification

  • Get-MgUser -UserId jason@contoso.com -Property AccountEnabled,SignInSessionsValidFromDateTime | Format-List shows the account state and the time sessions were last revoked.
  • Get-MgUserAuthenticationMethod lists only methods the user registered after recovery.
  • Get-MgUserOauth2PermissionGrant no longer lists the removed apps.
  • Get-InboxRule -IncludeHidden and Get-Mailbox show no attacker rules or forwarding.
  • The user's entry under Risky users shows Confirmed compromised or Remediated, and new sign-ins in the sign-in logs come only from expected locations.

Troubleshooting

The attacker still has access after the password reset. Sessions weren't revoked, an app password is still in use, a consented app still holds a grant, or an attacker-registered MFA method lets them pass a reset. Repeat Phase 1 and Phase 2. Remember that a valid access token can last up to an hour for apps that don't support CAE.

Search-UnifiedAuditLog returns exactly 100 results. That's the default limit. Add -SessionCommand ReturnLargeSet and a -SessionId, and keep the same SessionCommand value for the whole session; mixing ReturnLargeSet and ReturnNextPreviewPage on one session limits output to 10,000 results.

The search returns nothing for a single day. If StartDate and EndDate are the same date without a time, the range is zero. Include timestamps, and remember values without a time zone are treated as UTC.

Recent events are missing. Audit records for core services typically become available 60 to 90 minutes after the event, and Microsoft doesn't guarantee a specific time. Run the search again later before concluding the attacker did nothing.

No MailItemsAccessed records. Check that the user is licensed for it (E3 or E5 enables it by default) and that mailbox auditing is on. Absence of sync records doesn't prove no download: an attacker who synced with a client other than desktop Outlook, or worked offline afterwards, leaves less trace.

The user is blocked with error 50053 and "Sign-in was blocked by built-in protections due to high confidence of risk." ID Protection blocked a high-confidence risky sign-in, often from legacy authentication. After the investigation, have the user sign in with a modern client from a known location, or add a known corporate IP to trusted locations.

Closing checklist

  • Account disabled (in AD too for hybrid users), sessions revoked, compromised devices disabled.
  • User confirmed compromised in ID Protection or marked compromised in Defender.
  • Unknown MFA methods removed or re-registration required; app passwords deleted.
  • Untrusted OAuth2 permission grants removed; user consent settings reviewed.
  • Admin roles reviewed; inbox rules, forwarding and mailbox delegates cleaned up.
  • Sign-in logs, audit log and MailItemsAccessed results exported for the full window.
  • Sent mail reviewed with message trace; affected internal and external recipients identified.
  • Password reset securely, account re-enabled, MFA re-registered, sending restriction lifted.
  • Timeline and actions recorded in your incident log.

References

Questions people ask

Does resetting the password sign the attacker out of Microsoft 365?

Not by itself. Existing refresh tokens and app sessions can keep working, so also revoke sessions with Revoke-MgUserSignInSession or the Revoke sessions button on the user in the Microsoft Entra admin center. Access tokens already issued stay valid until they expire, which is 1 hour by default.

Should I disable the account or just reset the password?

Microsoft recommends disabling the compromised account until the investigation is complete. If you can't disable it, reset the password to a strong unique value, revoke sessions and replace app passwords, which a password reset doesn't revoke.

How do I know which emails the attacker read?

Search the unified audit log for the MailItemsAccessed operation for the user and the time window of the compromise. Bind records list individual messages by InternetMessageId; a sync record from the attacker's IP address means you should treat the whole folder, or mailbox, as exposed.

How far back can I search the audit log?

Audit (Standard) keeps records for 180 days. Users with an E5 license or the Purview Suite or E5 eDiscovery and Audit add-on get one year for Microsoft Entra ID, Exchange and SharePoint records by default. Export the evidence you need early so it doesn't age out.

Microsoft Entra IDExchange OnlineDefender XDRMicrosoft Purview Audit
  1. Block legacy authentication in Microsoft 365 without breaking printers

    Find every device and app that still signs in with legacy authentication, move printers and scanners to a supported sending method, then block legacy auth with Conditional Access.

  2. Fix Entra Connect AttributeValueMustBeUnique and duplicate proxy addresses

    Find which object already holds the duplicated proxyAddresses or userPrincipalName value, remove it from the right side, and confirm the next Entra Connect sync exports cleanly.

  3. A Microsoft 365 tenant security baseline you can apply in a day

    Harden a new or existing Microsoft 365 tenant in one working day: emergency access, admin roles, MFA and legacy auth, app consent, email protection, external forwarding, audit logging and Secure Score.