When I go through Microsoft 365 tenants for clients, I keep running into the same problems: leftover test tenants, stale accounts that are still active without MFA, and old app registrations with broad permissions. The Midnight Blizzard attack that Microsoft disclosed last week reads like a case study of all these weak spots lining up at once. The attackers used a non-production test account without multi-factor authentication, exploited an old OAuth application with privileged Exchange Online access, and then escalated by creating new malicious OAuth apps and a user who could grant consent.

Midnight Blizzard got in through forgotten accounts and an old app

Microsoft's official summary describes an attack chain that anyone who works with large tenants will recognise. A legacy test account, sitting outside the production environment and without MFA, was compromised through a password spray. The attackers then abused an old OAuth app that held the dangerous full_access_as_app permission for Exchange Online. To extend their access, they created new OAuth apps and a new user and used the consent process to grant themselves even more permissions.

One detail caught my attention. The attackers avoided detection based on IP reputation or geography by routing through a distributed residential proxy infrastructure, which makes the usual geo-based or impossible travel rules useless. If you want the full technical details, read the write-up on the Microsoft Security Blog.

The same weak spots behind the Midnight Blizzard OAuth apps attack show up in many tenants I review

In my tenant reviews, the gaps exposed by the Midnight Blizzard OAuth apps case are anything but rare:

  • Test and demo tenants get forgotten and are hardly ever maintained
  • Service and automation accounts often have no MFA
  • App registrations and enterprise apps with high privileges pile up without anyone noticing
  • User consent settings are far too permissive
  • Nobody monitors app credential changes or consent grants

Old test tenants are the worst offenders. In many environments I find app registrations and user accounts still in their default state, often with weak passwords or no MFA, because it was "only for testing". Sometimes these leftovers even connect back to production data or resources, and then they become a genuine risk. Cleaning them up is unglamorous work, but it belongs in any serious cloud security strategy.

MFA, an app inventory and consent controls make up the first checks

Tenant hygiene begins with MFA on every single account. Everyone agrees on that by now, yet old emergency accounts and service users still slip through regularly. I always advise going through the audit logs and making sure that anything with access to production uses strong authentication. Even better, disable legacy accounts you no longer need.

App registrations and their permissions are the next area that tends to get out of hand. In Entra ID, the "App registrations" and "Enterprise applications" blades show you which apps hold privileged roles, in particular those with full_access_as_app in Exchange or directory-wide read scopes. A quick PowerShell check looks like this:

Get-AzureADServicePrincipal -All $true | Where-Object {
  $_.AppRoles -match 'full_access_as_app'
}

In larger tenants, Defender for Cloud Apps offers a central app governance dashboard where you can keep track of risky apps and permissions.

Pro tip: Conditional Access (see also /blog/conditional-access-entra-id-getting-started), strict user consent controls and an admin consent workflow together block most malicious OAuth attacks, as long as you actually apply them everywhere.

User and admin consent need much tighter control in most tenants

This incident shows clearly how attackers use open user consent settings or poorly monitored apps to escalate privileges. Many tenants still allow far too much user consent for enterprise apps. As a minimum, limit user consent to verified permissions and trusted publishers, following Microsoft's guidance on user consent. Every app that needs high privileges should go through a mandatory admin consent workflow that you review on a regular basis.

The following Mermaid diagram shows what a sound admin consent process for OAuth apps in Entra ID looks like:

flowchart TD
    User["User requests app consent"]
    App["OAuth app asks for permissions"]
    Consent["Admin consent workflow"]
    Admin["Admin reviews & approves"]
    Grant["Permissions granted"]
    User --> App --> Consent --> Admin --> Grant

Figure: Admin consent workflow for OAuth apps in Entra ID

Go through all active app consents regularly, and remove unused or expired apps or rotate their credentials. After an incident like this one, that review is overdue.

Detection remains difficult when attackers hide behind distributed proxies

Monitoring and detection stay a weak point, particularly when attackers use a distributed proxy infrastructure as Midnight Blizzard did. Geo-based or impossible travel rules simply won't flag it. You have to look more closely at sign-in logs for unusual consent grants, new service principals or credential changes. In larger tenants, connecting a SIEM or using Defender for Cloud Apps to spot consent and app anomalies pays off.

Tenant hygiene matters more than zero-days in my view

The Midnight Blizzard OAuth apps attack shows once again that the biggest risks are usually not sophisticated exploits but forgotten test accounts and old apps nobody looks at anymore. MFA, controlled consent and a clean app inventory are basics. None of it is complicated, and it works. A tenant that is kept tidy and monitored carries far less risk. Spring cleaning in Entra ID is not optional, and you want to do it before someone else does it for you.