At 03:48 UTC on October 15, a tool using compromised ConnectWise application credentials failed to upload a certificate to a Microsoft 365 tenant. Fifty-five seconds later, another run retried that failure with waits of 3.5 and 7.1 seconds and succeeded. Huntress researchers Jonathan Semon and Rich Mozeleski found the change while reconstructing an attack on customers of ConnectWise Cloud Backup. The same investigation found requests continuing for 22 minutes after the Microsoft Teams service principal they targeted had been deleted.
For tenants that trusted ConnectWise applications, the records show a scripted tenant-ID sweep, retry logic added between runs, and loops that continued after a service principal was deleted. Microsoft attributes the campaign to Storm-0940 and says it used the ARTEX agent framework. Huntress rates the AI explanation low-to-medium confidence from its own telemetry and medium-to-high when Microsoft’s attribution is included. Huntress’s practical advice is direct: “The best method for defenders moving forward is to detect what the activity does, not how it paces itself.”
A vendor key crossed tenants
The attacker held a credential for a multi-tenant ConnectWise application. In a tenant that had authorized it, that identity could obtain an app-only token under permissions the customer had already granted. Interactive user sign-in was unnecessary. Huntress’s initial incident report identified the compromised Cloud Backup application and subsequent use of ConnectWise Cloud Management identities for Exchange Online, Teams and SharePoint Online. In two tenants it investigated, the Teams application granted itself Global Administrator and planted credentials on other applications. Disabling the original application alone leaves any planted credentials available for separate access.
Microsoft says the actor tried to sign in to more than 2,250 tenants using the compromised applications. Huntress observed a sorted sweep against almost 1,000 tenants in its telemetry, plus a separate burst of roughly 100 failed token requests in 10 seconds. The latter requests used a single-tenant secret against other tenants, where it could not authenticate. The two organizations measured attempted access across different tenant populations. Microsoft reports follow-on Graph and directory activity in multiple environments and says successful authentication alone does not mean customer data was accessed or exfiltrated.
Microsoft also reports bulk secret reads across multiple Azure Key Vaults through a compromised multi-tenant application, with key enumeration and a key-unwrapping operation. For Azure environments where that application had access, its hunting guidance includes CloudKeyVaultEvents for SecretGet and correlation with Storage and Azure Resource Manager activity. These observations do not establish Key Vault access in every ConnectWise tenant or compromise of ConnectWise’s backup archives.
The retries and orphaned requests
Between 03:42 and 03:57 UTC on October 15, Huntress saw secrets added, removed and added again, a certificate rejected for a thumbprint mismatch, and subsequent role changes. The next run incorporated retries; 47 seconds after the first tenant’s sequence, the tooling applied the credential changes in a second tenant. Later, when a role removal failed, the actor granted another role to a sibling principal. The change between runs is consistent with an operator adapting the tool, whether that operator was a person or an AI agent.
After the Teams principal was deleted, requests using it continued every four to eight seconds for 22 minutes, failing without adjustment. Huntress describes that stretch as background automation. A defender should investigate credential additions and role assignments even when the same campaign also produces noisy failed requests. Cadence or a slightly unusual python-requests/2.31 user agent can help pivot in retained logs; the directory changes identify the access that must be removed.
Huntress worked from Entra sign-in and directory audit records. Microsoft Graph reads require separate Graph activity logging for query-level visibility. Where that telemetry was enabled, preserve it alongside the sign-in records; where it was not, examine resource-access and audit records rather than treating a clean directory-change search as a clean data-access finding.
Trace the application and its descendants
Inventory the seven application IDs in ConnectWise’s technical guidance, including in tenants that previously authorized them, and record each local service-principal Object ID:
| Application | Application client ID |
|---|---|
| Cloud Backup | 506e08f9-6e9a-4da4-942b-a099a03644ae |
| Cloud Management | 2399d300-6fca-4e6a-a686-399fefe75b83 |
| Cloud Management - MS Teams | 24205314-2b89-4e07-a2a4-579e898a5640 |
| Cloud Management - Exchange Online | b78f6a77-d4e5-46fb-87e5-d1648bd02519 |
| Cloud Management - MS Graph | 0de14c77-b9b0-4137-9360-34878a929827 |
| Cloud Management - Partner Center | 412dcf96-176d-4b3a-a1b0-4981ad66971e |
| Cloud Management - SharePoint Online | b2b55f5b-7758-4719-8d8f-88ae172e6bdb |
Microsoft’s sample hunting queries enumerate three of these identities: Cloud Backup, Teams and MS Graph. Its immediate-action prose says four, but the query lists do not name a fourth. Use ConnectWise’s seven-ID inventory above for the full vendor-listed scope. Search by application ID rather than display name. Review successful and failed service-principal sign-ins from at least October 15; extend to October 1 where records permit. The published address 144.172.64[.]128 is a useful sign-in pivot, but investigate unexpected sources beyond the published addresses. Huntress observed that Microsoft-internal IPv6 addresses can also appear in this incident, and the shared range alone is not an actor identifier.
Preserve Entra sign-in and directory audit records, Microsoft Purview Audit, SIEM data and any configured Graph activity logs. Correlate unusual sign-ins with additions of application secrets or certificates, service-principal owners, app-role and consent grants, and privileged directory roles. Review mail and file access where available. Microsoft’s EntraIdSpnSignInEvents and GraphAPIAuditEvents examples correlate sign-ins and Graph requests. Use each product’s matching tables and verify collection coverage before interpreting missing results. For ongoing monitoring, alert on a service principal assigning itself Global Administrator or Privileged Role Administrator, adding credentials to another app, or granting a sibling principal a role. Baseline kiota-dotnet and the normal source range for these vendor apps, but retain raw user agents and sub-second timestamps for investigation.
Remove the planted access
Keep affected ConnectWise connections disabled pending ConnectWise’s formal restoration instructions. Huntress reported that ConnectWise had disabled relevant apps by October 17; confirm each tenant’s actual state and backup/restore arrangements with the vendor. Preserve the application configuration instead of deleting the enterprise app as a first response. Once authorized responders identify suspicious changes, remove unauthorized credentials, owners, grants and assignments, revoke unnecessary permissions, and rotate affected credentials. Confirm the vendor has reset its credentials before re-enabling an integration.
Recheck the application IDs and their sibling principals after containment. Expected state: affected connections stay disabled until formally restored, every surviving credential and high-privilege grant has an approved owner, and subsequent service-principal sign-ins and Graph activity match authorized vendor operations. The 55-second tool change is an investigative clue; the credential and role inventory is what tells you whether the attacker still has a way in.