In October 2026, an attacker used a stolen credential for ConnectWise Cloud Backup - the Microsoft 365 backup product formerly known as SkyKick - to sign in to hundreds of customer Microsoft 365 tenants. The incident response rightly focused on the immediate questions: which app IDs to disable, which IPs to search for, what the attacker touched.

I'll cover those below. But working in identity security, the part of this incident I keep coming back to is structural, and it applies to almost every Microsoft 365 tenant, whether it ever used SkyKick or not: a third-party app holding the right Microsoft Graph permissions is Global Administrator in your tenant - and the key to it lives in someone else's environment.

Written October 19, 2026, while the incident was still under investigation. The facts below reflect public reporting at that date, and I've flagged where sources disagreed or something was unconfirmed. Check the ConnectWise Trust Center for later updates. The identity analysis doesn't depend on those details.

What Happened

ConnectWise Cloud Backup - formerly SkyKick, acquired by ConnectWise in 2024 - runs as a multi-tenant Entra ID application. MSPs and customers consent it into their Microsoft 365 tenants so it can back up mail, OneDrive, SharePoint and Teams.

An attacker obtained a credential for that application. Because the credential belongs to the vendor's app registration, it lives in ConnectWise's own Entra tenant - and it works in every tenant where the app was consented. With it, the attacker signed in to customer tenants as the application. No user was involved, so user MFA and user Conditional Access never applied.

The key points, per Huntress, SpecterOps and the ConnectWise Trust Center:

At the time of writing, ConnectWise hadn't disclosed how the credential was stolen, and there was no attribution or government advisory. Sources also disagreed on the credential type (Huntress says a client assertion, i.e. certificate-based; some press says a client secret).

Why None of Your Usual Controls Mattered

This is the part that should bother every tenant owner. Walk through the controls most organizations rely on:

The only things that worked were controls that touch the grant itself: fewer permissions, a disabled app, an alert when an application does something, and logs that were already being kept.

My Analysis: The Permissions Were the Real Exposure

The stolen credential is the obvious story. From an identity standpoint, the more useful question is what made that credential worth stealing - and the answer is the Graph application permissions the app held in every tenant that consented to it.

Graph application permissions (app roles) are a separate authorization system from Entra directory roles. A service principal can be Global Admin-equivalent without holding a single directory role, which means it doesn't show up in your normal role reviews. Microsoft's own permissions reference warns about each of these:

Application permissionWhat it allowsBloodHound edge
Application.ReadWrite.All Manage all applications and service principals - including adding credentials to them, so the app can act as any other app and use its privileges AZMGAddSecret, AZMGAddOwner
AppRoleAssignment.ReadWrite.All Grant application permissions to any app - including itself AZMGGrantAppRoles
RoleManagement.ReadWrite.Directory Assign any Entra directory role - including Global Administrator - to any principal, including itself AZMGGrantRole

SpecterOps documented back in 2021 that each of these, on its own, is a path to Global Administrator. Microsoft's own guidance says service principals holding highly privileged access are control-plane - Tier 0 - assets. Yet Entra puts no "privileged" label on these grants, so nothing in the portal flags them.

Here's what that looks like in BloodHound, in my lab tenant: a "vendor backup app" service principal with these permissions. Every edge out of it is a way to reach Global Administrator - directly, by granting itself more permissions, or by adding a secret to another app that already holds the role.

BloodHound CE graph of a vendor backup app service principal with AZMGAddSecret, AZMGGrantRole, AZMGRoleManagement_ReadWrite_Directory and AZMGGrantAppRoles edges leading to another service principal, Microsoft Graph, Global Administrator and the tenant
BloodHound CE, lab tenant: one vendor app, several independent paths to Global Administrator.
BloodHound Legacy graph of the same vendor backup app showing the Application.ReadWrite.All and AppRoleAssignment.ReadWrite.All permission edges as well as AddSecret, GrantRole and GrantAppRoles
The same app in BloodHound Legacy, which also shows the underlying Application.ReadWrite.All and AppRoleAssignment.ReadWrite.All grants.

To be precise: no public source lists the exact permissions the ConnectWise apps held. An app making itself Global Administrator and then adding secrets to other apps is consistent with permissions like these, but that's inference. The point isn't this one vendor - it's that most tenants have granted permissions like these to some vendor, and have never looked.

If You Used ConnectWise Cloud Backup or Cloud Management

The published guidance from ConnectWise, Huntress and others converges on these steps:

  1. Disable, don't delete. Set each ConnectWise/SkyKick enterprise app to "Enabled for users to sign in? = No". Deleting destroys evidence and forces re-consent later.
  2. Match on Application ID, not name. Older tenants may show these apps as "SkyKick Cloud Manager".
  3. Preserve logs now. Entra sign-in and audit logs are kept for only 7 days on the free tier and 30 days on P1/P2. If you're on the free tier and haven't exported them, the October 15 records may already be gone.
  4. Review service principal sign-ins from October 13 onward. They're on a separate tab in the sign-in logs that the default view hides.
  5. Hunt for anything an application initiated - role assignments, new credentials, app role assignments, new owners, consent grants (queries below).
  6. Check every other app for new secrets or certificates. In ConnectWise's own words: "A replacement legitimate credential does not remove an attacker-added credential, role, or consent grant." A secret planted on another app survives every fix the vendor makes.
  7. Check Exchange for new inbox, forwarding and transport rules.

The application IDs ConnectWise published:

ApplicationApplication (client) ID
ConnectWise Cloud Backup506e08f9-6e9a-4da4-942b-a099a03644ae
Cloud Management - MS Teams24205314-2b89-4e07-a2a4-579e898a5640
Cloud Management - Exchange Onlineb78f6a77-d4e5-46fb-87e5-d1648bd02519
Cloud Management - SharePoint Onlineb2b55f5b-7758-4719-8d8f-88ae172e6bdb
ConnectWise Cloud Management2399d300-6fca-4e6a-a686-399fefe75b83
Cloud Management - MS Graph0de14c77-b9b0-4137-9360-34878a929827
Cloud Management - Partner Center412dcf96-176d-4b3a-a1b0-4981ad66971e

Attacker IPs reported: 144.172.64[.]128 (primary), 144.172.64[.]99 and 144.172.64[.]60. Use them to search your sign-in logs, not your firewall. Check the ConnectWise Trust Center for the current list - it has been updated several times.

For Every Tenant: Find Your Own "Vendor Backup App"

1. Inventory Third-Party Apps and Their Grants

List every service principal owned by another organization, and flag the dangerous Graph application permissions and any credentials on it. This only reads data:

Connect-MgGraph -Scopes 'Application.Read.All' $tenantId = (Get-MgContext).TenantId $microsoft = @('f8cdef31-a31e-4b4a-93e4-5f571e91255a','72f988bf-86f1-41af-91ab-2d7cd011db47') # Microsoft's own tenants $graphSp = Get-MgServicePrincipal -Filter "appId eq '00000003-0000-0000-c000-000000000000'" $roleName = @{}; $graphSp.AppRoles | ForEach-Object { $roleName[$_.Id] = $_.Value } $risky = 'Application.ReadWrite.All','AppRoleAssignment.ReadWrite.All', 'RoleManagement.ReadWrite.Directory','Directory.ReadWrite.All','Mail.ReadWrite' Get-MgServicePrincipal -All -Property id,displayName,appId,appOwnerOrganizationId,accountEnabled,passwordCredentials,keyCredentials | Where-Object { $_.AppOwnerOrganizationId -and $_.AppOwnerOrganizationId -ne $tenantId -and $_.AppOwnerOrganizationId -notin $microsoft } | ForEach-Object { $sp = $_ $perms = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -All | Where-Object ResourceId -eq $graphSp.Id | ForEach-Object { $roleName[$_.AppRoleId] } $hits = @($perms | Where-Object { $_ -in $risky }) if ($hits -or $sp.PasswordCredentials -or $sp.KeyCredentials) { [pscustomobject]@{ App = $sp.DisplayName AppId = $sp.AppId Enabled = $sp.AccountEnabled RiskyPermissions = $hits -join ', ' LocalSecrets = @($sp.PasswordCredentials).Count LocalCerts = @($sp.KeyCredentials).Count } } } | Sort-Object RiskyPermissions -Descending | Format-Table -AutoSize

Two things to look for in the output:

For the full picture - which of these apps can actually reach Global Admin, and how - collect your tenant with AzureHound and look at outbound edges from third-party service principals in BloodHound, as in the screenshots above.

2. Alert When an Application Changes Privileges

Here's the encouraging part: even when the attacker holds the vendor's credential, the changes they make happen in your tenant and land in your audit log. One Reddit admin's PIM alert fired on October 15 - a day before ConnectWise's first advisory.

The highest-fidelity signal for this whole class of incident is an application appearing as the initiator of a privilege change:

// Microsoft Sentinel / Log Analytics: privilege changes made BY an application AuditLogs | where TimeGenerated > ago(30d) | where OperationName in ( "Add member to role", "Add member to role outside of PIM (permanent)", "Add service principal credentials", "Add app role assignment to service principal", "Add owner to service principal", "Add owner to application", "Consent to application") or OperationName startswith "Update application – Certificates and secrets management" | where isnotempty(tostring(InitiatedBy.app.servicePrincipalId)) | project TimeGenerated, OperationName, Result, ActorApp = tostring(InitiatedBy.app.displayName), ActorAppId = tostring(InitiatedBy.app.appId), Target = tostring(TargetResources[0].displayName) | order by TimeGenerated desc

Expect some legitimate results - provisioning and management tools do make changes - so baseline it, then alert on anything new. Microsoft rates new credentials on an app, apps assigned to directory roles, and apps granted privileged Graph permissions as high-severity, and has Sentinel templates for each.

3. Shrink the Grants

4. Ask Your Vendors Harder Questions

Whoever controls the vendor's credential controls your tenant, so the vendor's key management is now your Tier 0 dependency. Add these to your vendor reviews:

5. Turn On the Logs You'll Wish You Had

The Bottom Line

Through an identity lens, this isn't really a story about one vendor. Admin consent to a multi-tenant app with these permissions is a standing delegation of control over your tenant to someone else's key management - and MFA, Conditional Access, GDAP and your firewall don't touch it.

So the useful question isn't "were we hit by SkyKick?" It's: which third-party service principals in our tenant can reach Global Admin today - and would we know within an hour if one did?