The ConnectWise breach is a supply chain intrusion in which AI agents did much of the legwork, and the uncomfortable part is how little they needed to break. Microsoft attributed it on October 21, 2026 to Storm-0940, a China-state aligned actor that used the ARTEX agent framework to try more than 2,250 Microsoft 365 tenants with the stolen identity of ConnectWise Cloud Backup (formerly SkyKick). If any ConnectWise or SkyKick application was ever consented in a tenant you run, disable it today, then go looking for credentials it may have added to your other apps, because those survive the vendor’s cleanup.
Picture the backup app the way an attacker does. To copy every mailbox, OneDrive and Teams channel it needs read access to all of them, and to restore them it needs write access too. Storm-0940 did not have to phish anyone or find a bug in Microsoft 365. It held that app’s credential and signed in as the app.
What happened in the ConnectWise breach
The timeline runs from a noisy password spray to a quiet credential plant, and the quiet part matters most.
- October 10 to 14, 2026: infrastructure at 144.172.64[.]99 sprayed 327 accounts across eight organizations, logging more than 151,000 failed sign-ins and peaking at 2,900 failures per minute on October 11, per Microsoft. None succeeded.
- October 15, 03:44 to 03:49 UTC: in one customer tenant, the ConnectWise Cloud Management app for Microsoft Teams added itself to Global Administrator. It then added client secrets to two other applications, one of them Huntress’s own security app, according to Huntress. The secrets were set to expire in 2028.
- October 15, from 06:13 UTC: the Cloud Backup identity signed in to tenants from 144.172.64[.]128, a hosting address, while its normal traffic comes from Azure private IPv6. Huntress later counted almost 1,000 Entra tenants with sign-in activity from that address, over 300 of them successful.
- October 16, 2026: Huntress published, and ConnectWise opened an incident naming the same IP.
- October 17, 07:00 UTC: ConnectWise disabled seven application identities and suspended Cloud Backup, SaaS Security and Cloud Management.
- October 19 to 21: ConnectWise reset every account and credential in the Cloud Backup environment and began a phased restoration, still investigating how the first access happened.
ConnectWise says its encrypted backup archives show no sign of access. That statement covers the archives, not your tenant, and ConnectWise says as much, because the service has no view into downstream Microsoft 365 environments.
Which applications are affected
Microsoft’s hunting queries list three application IDs. Huntress and ConnectWise’s own containment cover seven, so search for all of them, by ID rather than display name (older tenants may show “SkyKick Cloud Manager”).
| Application | Application ID |
|---|---|
| ConnectWise Cloud Backup | 506e08f9-6e9a-4da4-942b-a099a03644ae |
| ConnectWise 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 |
How the ARTEX agents worked the stolen identity
ARTEX is an open-source penetration testing framework, written in Go, in which LLM-driven agents run a test from reconnaissance to exfiltration with little human input. As they go, the agents build a graph of what they find. Zscaler documented the same framework behind a separate data theft campaign against South Korean financial firms that began in late September 2026, and its developer has since closed the source, which does nothing about copies already downloaded. Microsoft says Storm-0940 used it from as early as September 2026 and reached privileged cloud access in multiple environments less than three hours after first targeting them.
So was it really AI? Huntress’s second analysis is the most honest answer we have read. Scripts did the heavy lifting, including a loop that walked almost 1,000 tenants in ascending tenant ID order and a thread pool that fired about 100 requests in 10 seconds. Between runs, though, the tooling changed in under a minute. A failed certificate upload was followed 55 seconds later by a run that carried a new retry loop. Huntress puts its confidence that an LLM was involved at medium to high once Microsoft’s attribution is counted, and low to medium on its own telemetry.
We think the debate is less important than it looks. Huntress’s own conclusion is that cadence and retry patterns will fade as these tools improve, so you detect what the activity does, not how it paces itself. What it did was ordinary identity abuse, which is exactly why your existing logs can catch it.
How to detect ConnectWise app abuse in Entra ID
Start with the service principal sign-ins. In the Entra admin center, the default user sign-ins tab will not show them; open the service principal tab, filter by each ID above, and look for any address outside Microsoft and Azure ranges. Microsoft asks for a review back to at least October 15 and, for service principal sign-ins, back to October 1. A clean sign-in log does not clear you, because Graph directory reads leave no audit record.
The persistence is what outlives the vendor fix, so the rule below watches the audit log for a ConnectWise or SkyKick identity changing roles or credentials.
Data source: Microsoft Entra ID audit logs, exported through diagnostic settings (Azure Monitor properties.* schema).
title: ConnectWise Or SkyKick App Changes Roles Or App Credentials
id: 5b0d6f0e-2c8a-4f61-9d3e-8a7c41e2b9f4
status: experimental
description: Detects a ConnectWise or SkyKick application identity adding a directory role member or adding credentials to an application, the persistence pattern seen in the October 2026 ConnectWise Cloud Backup compromise.
references:
- https://www.microsoft.com/en-us/security/blog/2026/10/21/storm-0940-uses-artex-agentic-ai-connectwise-supply-chain-compromise/
- https://www.huntress.com/blog/vendor-credential-enables-unauthorized-access
author: MarkCyber Research
date: 2026-10-29
tags:
- attack.persistence
- attack.privilege-escalation
- attack.t1098.001
- attack.t1098.003
logsource:
product: azure
service: auditlogs
detection:
selection_actor:
properties.initiatedBy.app.appId:
- '506e08f9-6e9a-4da4-942b-a099a03644ae'
- '2399d300-6fca-4e6a-a686-399fefe75b83'
- '24205314-2b89-4e07-a2a4-579e898a5640'
- 'b78f6a77-d4e5-46fb-87e5-d1648bd02519'
- '0de14c77-b9b0-4137-9360-34878a929827'
- '412dcf96-176d-4b3a-a1b0-4981ad66971e'
- 'b2b55f5b-7758-4719-8d8f-88ae172e6bdb'
selection_activity:
properties.activityDisplayName|contains:
- 'Add member to role'
- 'Certificates and secrets management'
- 'Add service principal credentials'
condition: all of selection_*
falsepositives:
- ConnectWise Cloud Management assigning itself directory roles during legitimate setup; Huntress saw these apps take Exchange Administrator in about 50 tenants on October 15 with the vendor's kiota-dotnet user agent
level: high
That rule is tied to one vendor, and the next supply chain intrusion will use a different one. The KQL below, for Microsoft Sentinel’s AuditLogs table, catches the general move instead: any service principal that adds itself to a directory role, with the applications it gave new credentials to within 30 minutes.
Data source: AuditLogs (Microsoft Entra ID connector in Microsoft Sentinel).
let lookback = 30d;
let SelfRoleAdds = AuditLogs
| where TimeGenerated > ago(lookback)
| where OperationName == "Add member to role"
| extend ActorSpId = tostring(InitiatedBy.app.servicePrincipalId),
ActorApp = tostring(InitiatedBy.app.displayName)
| where isnotempty(ActorSpId)
| mv-expand Target = TargetResources
| where tostring(Target.id) == ActorSpId
| project RoleTime = TimeGenerated, ActorSpId, ActorApp, RoleResult = Result;
let CredAdds = AuditLogs
| where TimeGenerated > ago(lookback)
| where OperationName has "Certificates and secrets management"
or OperationName == "Add service principal credentials"
| extend ActorSpId = tostring(InitiatedBy.app.servicePrincipalId)
| where isnotempty(ActorSpId)
| project CredTime = TimeGenerated, ActorSpId,
ChangedApp = tostring(TargetResources[0].displayName);
SelfRoleAdds
| join kind=leftouter CredAdds on ActorSpId
| extend InWindow = CredTime between (RoleTime .. (RoleTime + 30m))
| summarize FirstRoleAdd = min(RoleTime),
ChangedApps = make_set_if(ChangedApp, InWindow, 20)
by ActorApp, ActorSpId, RoleResult
| order by FirstRoleAdd asc
Tune both with care. Some management tools legitimately grant themselves roles during onboarding, so baseline per application before alerting. Neither query sees what an app read through Graph, and app-only audit events carry no source IP, so pair any hit with the service principal sign-ins for the same window. Huntress separated vendor from attacker by user agent (kiota-dotnet for ConnectWise, Python-urllib/3.12 for the changes), which helps triage but is trivial to fake. Both rules map to ATT&CK T1098.003 and T1098.001.
Mitigation: disable, then hunt the credentials it left
Patching does not apply here, because nothing in your tenant was vulnerable. The steps come from Microsoft, Huntress and ConnectWise, in this order.
- Disable every application ID in the table, and do not delete them. Deleting removes consent and evidence, and Huntress notes that disabling does not touch backups ConnectWise already holds.
- Preserve Entra sign-in and audit logs and Purview audit records before they age out.
- Review client secrets and certificates on every app registration and enterprise app added since October 13, starting with management and security tools, and remove any you did not create. Disabling the ConnectWise apps does not remove these.
- Remove directory roles held by ConnectWise or SkyKick service principals that you did not grant on purpose.
- Keep the apps disabled until ConnectWise publishes reconnection instructions for your service.
The longer fix is treating app identities like the privileged accounts they are. Application management policies can block client secrets and cap credential lifetimes, and Conditional Access for workload identities can restrict where an app may sign in from. Our guide to non-human identity management walks through that inventory, and our earlier look at offensive agentic AI explains why the speed only goes up from here. If your tenants hold dozens of third-party apps with broad Graph rights, that review is the work our security engineering team does every week.
Bottom line
Disable all seven ConnectWise and SkyKick application IDs today, then audit every app credential added since October 13. The agents moved at machine speed through a door you had already opened for the backup app, so the hunt is for what that app did after it walked in.
