M365 Hardening

Storm-2949: How One Compromised Identity Became a Cloud-Wide Breach

Zack Jones ·
M365 HardeningThreat Intel Digest

On May 18, 2026, Microsoft Threat Intelligence published a detailed breakdown of Storm-2949, a threat actor that pivoted from a single compromised Entra ID account into full-scale exfiltration across Microsoft 365, Azure Key Vault, Azure SQL, Azure Storage, and production virtual machines. The attackers deployed no malware at any stage of the initial breach. No endpoint detection fired. The entire attack chain ran on legitimate administrative primitives: Graph API calls, RBAC assignments, VM extensions, and publishing profile exports.

For MSPs and vCISOs managing M365 and Azure environments, Storm-2949 is not an abstract nation-state case study. It is a precise demonstration of what happens when organizations misconfigure identity controls and treat endpoint security as the primary defensive layer. Every technique Storm-2949 used maps to a specific configuration gap that the CIS Microsoft 365 Foundations Benchmark already addresses.

This post walks the attack chain, maps each stage to CIS controls, and identifies the specific settings MSPs should verify in client environments this week.

How the Attack Started: SSPR Abuse and MFA Fatigue

Storm-2949 did not brute-force passwords or exploit a software vulnerability for initial access. The group initiated Self-Service Password Reset (SSPR) flows on behalf of targeted users, then used social engineering to get those users to approve the resulting MFA prompts. The technique is straightforward: an attacker triggers SSPR for a target account, calls the victim impersonating internal IT support, and asks them to approve the MFA prompt that appears on their device at that exact moment. The timing makes the prompt appear routine.

The targets were deliberate. Storm-2949 selected IT personnel and senior leadership, accounts most likely to hold privileged Azure RBAC assignments or broad access to sensitive SharePoint and OneDrive content.

Once the victim approved the MFA prompt, the attacker completed the password reset, disabled the legitimate user’s existing authentication methods, and enrolled Microsoft Authenticator on their own device. At that point, the attacker had locked out the real user and gained persistent, fully authenticated access.

CIS controls that address this stage

5.2.3.1 (L1): Ensure Microsoft Authenticator is configured to protect against MFA fatigue. This control requires number matching and additional context (application name and geographic location) to be displayed in push notifications. Number matching alone would have forced the victim to type a code from a screen they could not see, breaking the social engineering script Storm-2949 relied on.

5.2.2.5 (L2): Ensure phishing-resistant MFA strength is required for administrators. FIDO2 security keys, Windows Hello for Business, and certificate-based authentication are immune to the MFA fatigue technique entirely. If the compromised accounts had been restricted to phishing-resistant methods, the SSPR-based social engineering would have failed at the prompt stage.

5.2.2.6 (L1): Enable Identity Protection user risk policies. An SSPR flow initiated from an unfamiliar device or location, followed immediately by authentication method changes, should elevate user risk. With a user risk policy active and set to require password change or block access at medium risk, the account compromise would have triggered automated remediation before the attacker could proceed.

5.2.2.7 (L1): Enable Identity Protection sign-in risk policies. The sign-in itself, originating from an atypical location and device fingerprint immediately after a password reset, carries detectable risk signals. A sign-in risk policy set to require MFA or block at medium and high risk levels adds a second layer of automated response.

5.2.2.8 (L2): Ensure sign-in risk is blocked for medium and high risk. The L1 control (5.2.2.7) requires a policy to exist. This L2 control sets the threshold: block, not just challenge. For organizations where the cost of a false positive block is lower than the cost of a compromised privileged account, this is the appropriate setting.

Microsoft’s own post-incident recommendation is specific: configure a Conditional Access policy targeting the “Register security information” user action and require phishing-resistant authentication strength. That single policy breaks the MFA-stripping step in the Storm-2949 chain, because the attacker cannot register their own authenticator device without satisfying a phishing-resistant challenge they cannot intercept.

Lateral Movement: Graph API Reconnaissance and M365 Data Exfiltration

With a valid session established, Storm-2949 moved to reconnaissance. A custom Python script called the Microsoft Graph API to enumerate users, applications, and service principals across the tenant. The goal was mapping privileged identities and locating additional footholds.

The attacker then targeted Microsoft 365 data stores. The attacker searched SharePoint and OneDrive for IT documentation covering VPN configurations and remote access procedures. In one instance, Storm-2949 used the OneDrive web interface to download thousands of files in a single bulk action.

This stage of the attack produced no malware alerts, no anomalous process executions, and no endpoint telemetry worth investigating. The data exfiltration used the same web interface and API surface that legitimate users and administrators use every day.

CIS controls that address this stage

5.2.2.3 (L1): Ensure Conditional Access policies block legacy authentication. Legacy authentication protocols bypass Conditional Access entirely. If any path to the tenant still allows legacy auth, an attacker with valid credentials can sidestep every Conditional Access policy in the tenant.

5.2.2.4 (L1): Ensure sign-in frequency is enabled and browser sessions are not persistent for administrative users. Shorter session lifetimes limit the window of exploitation after credential compromise. If the compromised account had a sign-in frequency of one hour instead of the default persistent session, the attacker’s window for Graph API enumeration and bulk download would have been significantly narrower.

5.2.2.16 (L2, new in v7.0.0): Ensure Token Protection is enforced for session tokens. Token Protection cryptographically binds session tokens to the device that received them. Even if Storm-2949 had exfiltrated a session token, it could not have been replayed from the attacker’s own infrastructure.

Vertical Escalation: Azure Key Vault, SQL, and Storage

The attack did not stop at M365 data. Storm-2949 escalated vertically into the Azure control plane. The compromised account held Owner rights on an Azure Key Vault containing production credentials. Over an approximately four-minute window, the attacker manipulated Key Vault access policies, extracted dozens of secrets including database connection strings and identity credentials, and moved to the next target.

With Key Vault secrets in hand, Storm-2949 modified Azure SQL firewall rules to temporarily allow connections from attacker-controlled IPs, connected using the harvested credentials, exfiltrated database contents, then deleted the firewall rules to cover their tracks.

Azure Storage accounts followed the same pattern. The attacker used microsoft.storage/storageaccounts/write to enable public access from specific IPs, then listkeys to harvest SAS tokens and account keys. A custom Python script built on the Azure Storage SDK downloaded large volumes of blob data over several days.

Why CIS M365 controls still matter at this stage

The Azure control plane is outside the direct scope of the CIS Microsoft 365 Foundations Benchmark, which focuses on the M365 and Entra ID layers. But gaps in the CIS controls at the identity layer are what allowed Storm-2949 to reach Azure resources unchallenged.

Every Azure RBAC assignment, every Key Vault access policy, every SQL firewall rule change authenticates through Entra ID. Conditional Access policies, sign-in risk policies, and session controls at the identity layer are the enforcement point. If those controls had caught the initial compromise or the post-compromise session, the Azure escalation would never have occurred.

This is the structural argument for identity-layer hardening: Azure and M365 share the same identity plane. Hardening that plane hardens both.

VM Compromise: Living Off the Cloud

In the final stage, Storm-2949 deployed the VMAccess extension to create a new local administrator account on a targeted Azure VM. VMAccess is a legitimate Azure VM extension designed to help administrators restore access when credentials are lost. Storm-2949 used it as a backdoor.

From there, the attacker used the Run Command feature to execute PowerShell scripts inside the VM, exploiting the VM’s managed identity to access additional Azure resources and disabling Microsoft Defender Antivirus protections. When gateway protections blocked direct access to a primary production web application, Storm-2949 bypassed the restriction by compromising auxiliary web applications and extracting deployment credentials through Azure publishing profiles.

In the later stages, the group deployed ScreenConnect for persistent remote access and attempted to wipe forensic evidence.

The endpoint security gap

This is where the Storm-2949 case makes its sharpest point about defensive architecture. The VM compromise, the Defender disablement, and the ScreenConnect deployment are all detectable by endpoint security tooling. But by the time the attack reached the VM layer, the attacker had already exfiltrated data from M365, Key Vault, SQL databases, and Storage accounts. The attacker accomplished the bulk of the damage entirely through API calls and web interfaces that never touched an endpoint agent.

An organization that relies primarily on EDR and endpoint hardening would have detected activity in the final stage and missed everything that preceded it.

What MSPs Should Verify This Week

The Storm-2949 attack chain maps cleanly to a short list of CIS M365 Benchmark controls. For any client environment running M365 with Entra ID, these are the settings to verify now.

MFA configuration:

  • Microsoft Authenticator number matching is enabled (5.2.3.1)
  • Phishing-resistant MFA is required for all administrative roles (5.2.2.5)
  • Conditional Access requires phishing-resistant authentication strength for the “Register security information” user action (Microsoft’s specific recommendation from the Storm-2949 disclosure)

Identity Protection:

  • User risk policy is enabled and set to at least medium risk (5.2.2.6)
  • Sign-in risk policy is enabled and set to at least medium risk (5.2.2.7)
  • For L2 environments: sign-in risk is set to block at medium and high (5.2.2.8)

Session controls:

  • Legacy authentication is blocked via Conditional Access (5.2.2.3)
  • Sign-in frequency is configured for administrative users with non-persistent browser sessions (5.2.2.4)
  • Token Protection is enforced where supported (5.2.2.16)

SSPR hygiene:

  • All privileged users have pre-registered MFA methods (prevents malicious first-time registration during SSPR abuse)
  • SSPR activity reports are reviewed at least weekly (5.2.4.2)

These are not aspirational recommendations. They are specific, testable configurations. Each one maps to a technique Storm-2949 used in a documented attack against a real organization.

The Wider Context: Entra ID Under Pressure

Storm-2949 is not the only recent signal that identity-layer security in Entra ID environments requires closer scrutiny. In April 2026, Microsoft patched CVE-2026-35431, a CVSS 10.0 server-side request forgery vulnerability in Entra ID Entitlement Management. The vulnerability required no authentication and no user interaction to exploit. Microsoft fixed it server-side; customers needed to take no action.

But the combination of a CVSS 10.0 in the identity governance plane and a documented identity-first attack campaign in the same quarter reinforces the same conclusion: the identity layer is the primary attack surface for cloud environments, and it requires the same rigor and frequency of assessment that organizations have historically applied to network perimeters and endpoints.

Configuration-Level Assessment Catches What Tooling Misses

Storm-2949 used 13 distinct techniques chained together. None of them required malware. None of them exploited a software vulnerability. Every one of them exploited a configuration gap or a missing policy.

Automated compliance scanners check whether a control exists. They verify that a Conditional Access policy is present. They do not evaluate whether the policy’s conditions, exclusions, and grant controls are configured to actually stop an attack chain like Storm-2949. That evaluation requires a practitioner who understands how the controls interact and how an attacker moves between them.

That is the gap a CIS M365 benchmark assessment fills. Not the presence of controls, but the effectiveness of their configuration against documented attack techniques.


The Storm-2949 attack chain, technical details, and Microsoft’s mitigation recommendations are sourced from Microsoft Threat Intelligence’s May 18, 2026 disclosure: How Storm-2949 turned a compromised identity into a cloud-wide breach. CIS control references are based on the CIS Microsoft 365 Foundations Benchmark v5.0.0 and v7.0.0.