Email Security

Email Forwarding Attack on Microsoft 365: Detection, Prevention, and Response

Auto-forwarding is the most common way attackers stay inside your tenant after the initial compromise. Here is how the rules work, how they hide, and how to find them before they cost you a customer.

By , CTO · Published · Last updated

TL;DR

  • Auto-forwarding is the first thing an attacker sets up after stealing a password. It survives password resets, MFA changes, and session revocation in many configurations because the rule lives on the mailbox, not the session.
  • There are four separate mechanisms attackers use to forward mail out of M365, and a tenant-wide block on one of them does not automatically close the others.
  • Hidden rules are not theoretical. Attackers name rules with whitespace, single periods, or null characters so they do not render in Outlook. Rules created via EWS sometimes do not appear in Outlook at all.
  • The fix has two halves: tenant-wide prevention (remote-domain config, Conditional Access, Defender anti-phishing, audit alerts) and a monthly PowerShell sweep that finds rules created since the last sweep.
  • When you find an active forwarding rule, do not delete it first. Document, disable, preserve evidence, then expand the search. It is rarely just one mailbox.

What the attack actually looks like

The attacker phishes a password, or buys one off a credential dump, or proxies a session through Evilginx and harvests the post-MFA cookie. The route in matters less than what happens next.

Once they are inside a mailbox, they almost never spam, exfiltrate, or pivot immediately. They set up forwarding and they wait. A copy of every incoming message, or every message matching certain keywords, lands in a Gmail or ProtonMail inbox they control. The compromised user sees nothing change. Mail still arrives. Mail still gets read. Outlook does not pop a banner that says "by the way, a stranger is also reading this."

For two or three weeks the attacker watches. They learn who pays whom, when invoices go out, who the AP contact is at the largest customer, and what a real wire-instructions email from the controller looks like. When they have enough context, they swap one ACH routing number on a real invoice and send it from the legitimate mailbox. The downstream impact pattern, end-to-end, is in the sibling guide on business email compromise prevention.

The reason forwarding is the persistence technique of choice is operational. A session cookie can be revoked. A password can be reset. But an inbox rule that says "forward everything to gmail-address" lives on the mailbox object, and unless someone goes looking for it, it keeps running long after the security team has declared the incident closed. We have seen rules survive complete tenant lockdowns because the responder reset the password, revoked sessions, and never opened PowerShell.

Why these rules are hard to spot

Three things make forwarding rules unusually slippery.

Outlook does not surface them well. The Rules dialog in desktop Outlook shows rules created from inside Outlook. It does not always show rules created via Outlook on the web, via Exchange Web Services, or via the Microsoft Graph API. A user looking at Outlook can have an empty Rules list and a live forwarding rule running on every inbound message.

Attackers name them to hide. A rule called "." (one period) renders in some UI views as a blank line. A rule named with three space characters renders as nothing visible in others. A rule named with a null byte or a zero-width space renders inconsistently across clients. The rule itself is fine. The name is engineered to disappear.

The conditions can look harmless. A rule that says "if subject contains 'invoice' then move to RSS Feeds and mark read" is not obviously a forwarding rule. The forwarding can happen in the action itself (forward to external address), or in a chained delivery setting on the mailbox, or in a delegated-access pattern where the attacker logs in as the delegate and reads the original mailbox's mail directly. Looking at the rule list with a "is anything forwarding externally" filter misses most of those.

That is why the answer is never just "open Outlook and check." The answer is PowerShell, run tenant-wide, against every mailbox, on a schedule.

The four forwarding mechanisms attackers exploit

Treat these as separate attack surfaces. Closing one does not close the others.

1. Inbox rule with "redirect to" or "forward to." Created via Outlook, OWA, EWS, or Graph. Lives on the mailbox in the Inbox Rules collection. Easiest to create, easiest to find when you know to look. The same rule can also move the original to RSS Feeds or Conversation History so the user never sees the trigger message land in their inbox. The redirect variant is worse than the forward variant: redirected mail keeps the original sender in the From line, which means the attacker's copy looks like it came directly from your customer rather than from the compromised user.

2. Mailbox-level forwarding via Set-Mailbox. A separate setting from inbox rules. Set with ForwardingSmtpAddress or ForwardingAddress, plus the DeliverToMailboxAndForward flag that decides whether the original copy stays in the user's mailbox. Does not appear in the user's Outlook Rules dialog under any circumstance because it is not a rule. Requires admin or delegated access to create, which is one reason it shows up in compromised-admin scenarios.

3. Delegated mailbox access with auto-forward on the delegate's box. The attacker compromises an admin or a delegated user, grants themselves Full Access on a target mailbox, then sets a forwarding rule on the delegate account they control. Mail arrives at the target, gets read by the delegate session, and forwards out from the delegate. The target mailbox shows no rules and no forwarding. Hunting for this one requires reviewing the audit log for Add-MailboxPermission events, not just the mailboxes themselves.

4. SharePoint and Teams sharing as the exfiltration channel. When tenant-wide forwarding is blocked, sophisticated attackers stop forwarding entirely and pivot to file sharing. They share folders, channels, or files with an external address from a compromised account, rely on the default sharing permissions to allow it, and pull the data through that channel. Not technically a forwarding attack, but the same operational goal and the same root cause (a compromised user with sufficient permissions). Worth mentioning because shutting off email forwarding without locking down external sharing just moves the leak.

Coverage of which Conditional Access and identity controls close the door at the front, before the attacker is in a position to set any of these up, is in the SecureYourTenant guide on blocking legacy authentication. Forwarding is the back-end persistence technique. Legacy auth is one of the front doors that gets the attacker into the position to use it.

Detection: the six PowerShell queries that find forwarding tenant-wide

These are the queries we run on every incident response and every monthly tenant audit. Connect to Exchange Online with Connect-ExchangeOnline and to Microsoft Graph with Connect-MgGraph -Scopes "Mail.ReadBasic.All","AuditLog.Read.All" before running them.

Query 1: All mailboxes with auto-forwarding enabled at the mailbox level. This catches mechanism 2 above.

Get-Mailbox -ResultSize Unlimited |
  Where-Object { $_.ForwardingSmtpAddress -or $_.ForwardingAddress } |
  Select-Object UserPrincipalName,
                ForwardingSmtpAddress,
                ForwardingAddress,
                DeliverToMailboxAndForward |
  Export-Csv mailbox-forwarding.csv -NoTypeInformation

Query 2: All inbox rules tenant-wide that redirect or forward externally. This catches mechanism 1. Note the explicit pull of every rule including hidden ones.

$tenantDomains = (Get-AcceptedDomain).DomainName

$findings = foreach ($mbx in Get-Mailbox -ResultSize Unlimited) {
    Get-InboxRule -Mailbox $mbx.UserPrincipalName -IncludeHidden |
      Where-Object { $_.ForwardTo -or $_.RedirectTo -or $_.ForwardAsAttachmentTo } |
      ForEach-Object {
          $targets = @($_.ForwardTo) + @($_.RedirectTo) + @($_.ForwardAsAttachmentTo)
          $external = $targets | Where-Object {
              $addr = ($_ -as [string])
              $addr -match '@' -and -not ($tenantDomains | Where-Object { $addr -like "*@$_*" })
          }
          if ($external) {
              [PSCustomObject]@{
                  Mailbox     = $mbx.UserPrincipalName
                  RuleName    = $_.Name
                  Enabled     = $_.Enabled
                  External    = ($external -join '; ')
                  Conditions  = $_.Description
              }
          }
      }
}

$findings | Export-Csv inbox-rules-external.csv -NoTypeInformation

Query 3: Disable forwarding tenant-wide via remote domain config. Run this after you have found and triaged everything in queries 1 and 2. It blocks new automatic forwarding to external recipients at the transport layer.

Set-RemoteDomain -Identity Default -AutoForwardEnabled $false

Get-RemoteDomain -Identity Default |
  Select-Object Name, DomainName, AutoForwardEnabled

The next three queries are the ones most responders skip and most attackers count on you skipping.

Query 4: Find rules with suspicious naming patterns. Whitespace-only names, single-character names, names with non-printable characters.

foreach ($mbx in Get-Mailbox -ResultSize Unlimited) {
    Get-InboxRule -Mailbox $mbx.UserPrincipalName -IncludeHidden |
      Where-Object {
          $name = $_.Name
          [string]::IsNullOrWhiteSpace($name) -or
          $name.Length -le 2 -or
          $name -match '[\x00-\x1F\x7F]' -or
          $name -match '^[\s\.]+$'
      } |
      Select-Object @{n='Mailbox';e={$mbx.UserPrincipalName}},
                    Name, Enabled, ForwardTo, RedirectTo, MoveToFolder
}

Query 5: Audit log review for new forwarding rules in the last 90 days. Catches recent activity even if the rule has since been deleted.

Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-90) -EndDate (Get-Date) `
  -Operations "New-InboxRule","Set-InboxRule","Enable-InboxRule",
              "Set-Mailbox","Add-MailboxPermission" -ResultSize 5000 |
  Select-Object CreationDate, UserIds, Operations, ObjectId, AuditData |
  Export-Csv forwarding-audit-90d.csv -NoTypeInformation

Query 6: Mailbox permission grants in the last 90 days. Catches mechanism 3 (delegated-mailbox forwarding).

Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-90) -EndDate (Get-Date) `
  -Operations "Add-MailboxPermission","Add-RecipientPermission" -ResultSize 5000 |
  Select-Object CreationDate, UserIds, Operations, ObjectId, AuditData

Run queries 1, 2, and 4 monthly. Run queries 5 and 6 after any sign-in anomaly, any user-reported phishing click, or any unusual help-desk pattern. Diff the outputs against last month's run. New entries are findings until proven benign. The full self-assessment for tenants that want a quick read on whether anything is already running is in our guide on whether your M365 email is compromised.

The four hidden-rule techniques attackers use

Each one defeats a different default check. Knowing the catalog matters because the absence of a visible rule does not mean the absence of a rule.

  1. Whitespace-only names. The rule is named with three space characters, or a tab, or a non-breaking space. Outlook renders the row as a blank line. Most users skim past it. Query 4 above flags it.
  2. Single-character names. A rule called "." or "," or "-". The row appears in Outlook but reads as a typo or a placeholder. Same query catches it.
  3. Conditions that appear to do nothing. The rule's visible action is "mark as read" or "move to RSS Feeds." The forwarding part is buried in a secondary action that some Outlook clients do not display in the summary view. The user opens the rule, sees "mark as read," closes it, and moves on. Always read the rule's full action set, not the summary.
  4. Rules created via Exchange Web Services or Graph that bypass Outlook entirely. The rule lives on the mailbox object and runs in transport, but Outlook's Rules dialog never queries the same surface where it was written. Get-InboxRule -IncludeHidden finds it. The Outlook UI does not.

Attackers chain these. A rule named with whitespace, with a misleading visible action, created via EWS, set to forward to a hijacked Gmail account that itself forwards to an offshore burner address. Three layers of indirection between you and the exfiltration target. Each layer breaks one default detection.

Tenant-wide prevention

Four controls. Stack them. Any one alone has a known bypass.

Block automatic external forwarding via remote-domain config. The query 3 command above (Set-RemoteDomain Default -AutoForwardEnabled $false) prevents new mailbox-level and rule-based automatic forwarding to recipients outside your accepted domains. Tenants created after 2020 ship with this set to $false via the outbound spam policy default; tenants created before 2020 are still wide open unless an admin changed it. Verify with Get-RemoteDomain Default | fl AutoForwardEnabled.

Conditional Access policy blocking external recipients on suspicious sessions. A Conditional Access policy that requires sign-in risk = low and device compliance for any session that uses Exchange Online sets a quality bar on the session before any forwarding rule can be created. It does not block rule creation directly, but it raises the cost of getting into the mailbox in the first place. The companion control list, with rollout sequence, is in the SecureYourTenant guide linked above.

Defender for Office 365 anti-phishing rule on outbound forwarding. Defender's outbound spam policy has a setting under Anti-spam → Outbound spam policy → Forwarding rules. Set "Automatic forwarding rules" to Off, Forwarding is disabled in the default policy. This is a separate enforcement point from the remote-domain config above. Belt and suspenders.

Audit alert on new inbox rule creation. An alert policy that fires when any user creates a new rule with a forwarding or redirect action. Configure it under Defender → Email & collaboration → Policies & rules → Alert policy → New alert policy. Activity: "Created forwarding/redirect rule." Threshold: every occurrence. Recipient: whoever monitors tenant security. This is the one that catches the attack as it happens, instead of at the next monthly audit.

One thing none of these does: stop a malicious rule that was already created before you turned them on. That is what queries 1, 2, and 4 are for. Prevention plus baseline audit. Skip either half and you are guessing.

Response when you find an active forwarding rule

The instinct is to delete it. Resist that. The rule is your highest-value piece of evidence.

The right sequence:

  1. Document before you touch. Screenshot or export the rule with all conditions, actions, and target addresses. Note the creation timestamp from the audit log. Copy the exact target email address. You will need this for the insurance claim and possibly for law enforcement.
  2. Disable, do not delete. Set the rule's Enabled property to $false. This stops further exfiltration immediately while preserving the rule object for evidence. Deletion removes the rule from Get-InboxRule output, and although the audit log still has the creation event, you have lost the live artifact.
  3. Reset the password and revoke all sessions. Revoke-MgUserSignInSession -UserId [email protected] ends every active session including OAuth refresh tokens. Combined with the password reset, this evicts the attacker from the mailbox.
  4. Hunt for additional rules across the tenant. It is rarely just one mailbox. Run queries 1, 2, and 4 against every mailbox, not just the one you found. Attackers who get one mailbox usually move laterally and set rules on three to five more before they start exfiltrating, especially if the original compromise was a privileged account.
  5. Pull the audit log for everything that mailbox did since the rule was created. Sent mail, files accessed, calendar items shared, OAuth consents granted. Anything in the window from rule creation to your discovery is potentially attacker activity, and you need to know which actions were the user's and which were not.
  6. Notify customers if the exfiltrated thread included sensitive third-party data. If the compromised mailbox contained customer PII, financial data, or contract terms, your contractual notification window is probably 72 hours. The legal sequence and templates are in the BreachShield365 M365 tenant compromise recovery checklist.

One more thing. The forwarding target address is itself worth investigating. Send a careful query against the audit log of any other tenant you operate to see whether the same external address shows up there. We have seen attackers reuse the same Gmail target across half a dozen unrelated victims when the operation was run by the same crew. A reused target address is also useful evidence for IC3 reporting and any subsequent law-enforcement work.

The full sequence and the order it has to happen in (so you do not blow up the evidence chain you need for the insurance claim) is in the broader Microsoft 365 email security checklist, which sequences this against the rest of the mailbox-incident workflow.

What this looks like in a real tenant

A 28-person property-management firm called us in October. Their bookkeeper had clicked a link two weeks earlier, entered her password on what she thought was a OneDrive page, and approved an MFA push. She forgot about it.

For 16 days the attacker read her mail. They learned she handled deposits for tenant security accounts, that the pattern was a wire from the property owner to a holding account each time a new tenant moved in, and that the bookkeeper rarely picked up the phone. On day 17 they sent a wire-instructions email from her own mailbox to a property owner asking them to redirect the next $14,000 deposit to "the new escrow account." The owner wired the money. The bookkeeper noticed nothing because the attacker's rule was: subject contains "wire" or "deposit" then move to RSS Feeds and mark read.

When we pulled queries 2 and 4 against her mailbox, we found the rule. Name was a single period. Action was move-to-folder plus forward-to a Gmail address that contained the bookkeeper's first initial and the firm's town name. The audit log showed the rule was created 13 minutes after the phishing-page sign-in. Query 6 showed no other mailboxes had been delegated, so the attacker had stayed local.

The recoverable lessons: the password reset two days after the wire fraud (which the firm had done correctly) did not remove the rule. The "is everything okay now" check from the IT vendor was Outlook's Rules dialog, which did not display the rule because of the period-only name. The first time the rule actually showed up was when we ran Get-InboxRule -IncludeHidden. The attacker still had read access for nine days after the password reset before the firm engaged us.

Nothing exotic happened in that case. The attacker used mechanism 1, technique 2 (single-character name). A single PowerShell query, run once, would have surfaced it on day one.

Common questions

If I reset the password, am I done?

No. Password reset evicts the attacker from new sign-ins. It does not remove inbox rules, mailbox-level forwarding, OAuth grants, or delegated permissions the attacker created while they were inside. Every one of those is a separate persistence mechanism that survives the reset. Always run the queries above after any compromise event, even ones that "look small."

Will Set-RemoteDomain -AutoForwardEnabled $false break legitimate forwarding for users who have a real reason to forward externally?

Yes, by design. That is the whole point. If a user genuinely needs to forward to a personal address (for example, a contractor whose mail you want copied to their primary inbox), set up a mail-enabled contact for them and route through a transport rule with explicit logging, rather than relying on user-controlled inbox forwarding. The mail-enabled-contact path is auditable; user-set forwarding is not. The trade is small for the visibility gain.

How often should I actually run the audit queries?

Monthly for queries 1, 2, and 4. Immediately after any sign-in anomaly, password reset, OAuth consent grant, or user-reported phishing click for queries 5 and 6. The monthly cadence catches drift. The event-triggered cadence catches active incidents. A scheduled task that runs the queries weekly and emails the diff to whoever owns tenant security is the version we deploy for managed clients.

Does Defender for Office 365 catch this on its own?

Defender's outbound spam policy blocks new automatic external forwarding when set correctly, and Defender's alert policies fire on new rule creation if you turn that on. Neither one finds existing rules that were created before you enabled the policy. Defender is the future-state control. PowerShell is the current-state audit. You need both.

Can the attacker create a rule that survives even Get-InboxRule -IncludeHidden?

In some configurations, yes. Mechanism 2 (mailbox-level forwarding) does not appear in Get-InboxRule output at all because it is not a rule; it is a mailbox property. Query 1 catches it. Mechanism 3 (delegated access with forwarding on the delegate) does not appear on the target mailbox under any query because the rule is on a different mailbox; query 6 plus a follow-up query 2 against the delegate's mailbox catches it. The full audit needs all six queries, run in order. Skipping any of them leaves a known bypass.

Get the free Email Compromise Self-Check

No spam. Unsubscribe anytime.

Run the Audit Against Your Tenant

A free M365 risk check shows whether forwarding controls are in place and whether any rules look suspicious right now.