Yes. Most Microsoft 365 backup services run as a multitenant app that an administrator consented to, with application permissions that let it read, and often write, every mailbox, OneDrive and SharePoint site without any user signed in. If the vendor's app credential is stolen, the attacker inherits that access in every customer tenant until someone disables the app.
That is not a flaw in backup products. It is how app-only access in Microsoft Entra ID is designed to work, and Microsoft's own documentation lists backup as a standard reason to use it. The useful questions are which apps hold this kind of access in your tenant, whether any of it can be narrowed, and what you do in the first hours after a vendor tells you its app identity was abused.
Key takeaways
- A Microsoft 365 backup app is a service principal in your tenant. The credential it signs in with lives in the vendor's tenant, not yours, so you cannot rotate it and you usually cannot see it.
- Application permissions (also called app roles) are not limited by any user's rights. Microsoft's docs say an app granted the application permission
Files.Read.All"is able to read any file in the tenant." - You can list every third-party app and the exact permissions it holds with a short Microsoft Graph PowerShell script. Do it before an incident, not during one.
- Disabling a vendor's service principal in your tenant stops new sign-ins. It does not undo changes the attacker already made, and tokens issued before the shutdown can keep working until they expire.
- You can narrow some access. Exchange Online RBAC for Applications scopes mail permissions to a set of mailboxes, and SharePoint Selected scopes limit an app to named sites. Conditional Access for workload identities does not cover third-party multitenant apps.
- SOC 2 and ISO 27001 both expect you to assess vendors with this level of access, review them on a schedule and keep evidence. A vendor's SOC 2 report also lists controls it expects you to run.
- Keep a second, independent copy of the data you cannot afford to lose, held by an identity that is not the same app you are worried about.
Why this question is being asked now
In October 2026, ConnectWise suspended its Cloud Backup service (formerly SkyKick) after unauthorized access to its application identities was used to reach customer Microsoft 365 tenants. The vendor is named here because its own advisory names the product and the affected identities. The details below come from that advisory and from reporting that cites it. The story is still moving, so treat counts as provisional.
| Date (2026, UTC) | What happened | Source |
|---|---|---|
| 13 to 15 October | Partners are told to review tenant activity from 13 October onward. Help Net Security, citing a security firm's analysis, reports sign-ins as the backup app across customer tenants on 15 October. | Kaseya weekly roundup; Help Net Security |
| 15 October | ConnectWise says it discovered the problem; Kaseya's roundup says Microsoft reported unauthorized authentication attempts from an IP address that day. | Help Net Security; Kaseya |
| 16 October, 17:47 | ConnectWise publishes its original advisory. | ConnectWise Trust Center |
| 17 October, 07:00 | ConnectWise disables seven application identities, one for Cloud Backup and six for Cloud Management (Teams, Exchange Online, Microsoft Graph, Partner Center, SharePoint Online and a general one), and revokes the certificates used for affected connections. | ConnectWise Trust Center; The Hacker News |
| 18 October | Advisory update: "Previously issued access tokens may remain usable until they expire or are otherwise invalidated." Disabling the apps does not reverse changes already made in a tenant. | ConnectWise Trust Center |
| 23 October, 01:00 | Latest update at the time of writing: restoration work in progress, partners told to keep affected connections disabled until formal instructions apply to their service. | ConnectWise Trust Center |
Two facts in the advisory matter for every admin. ConnectWise says it "cannot determine" whether a specific customer tenant was affected, because it has no visibility into customer environments, and its vendor side actions do not change the enterprise application inside each tenant. The cleanup is yours.
Help Net Security reports a security firm's count of at least 162 Microsoft 365 tenants with confirmed unauthorized access. ConnectWise says it has no indication its stored backup archives were accessed, and that whether a product vulnerability contributed "has not been established." The vendor's archives and the live data in your tenant are separate questions.
For the broader version of this problem across all SaaS connections, see every connected app is a durable credential. For the general playbook when any supplier reports a breach, see a vendor just told you they were breached.
What permissions does a typical Microsoft 365 backup app hold, and why does it need them?
A backup service has to read everything it protects, on a schedule, with nobody at the keyboard. In Microsoft's model that is app-only access. Microsoft's overview of permissions and consent describes app-only access as the case where "the application acts on its own with no user signed in" and names "automation, and backup" as typical uses.
To restore, most services also need to write. A restore puts mail back into a mailbox, files back into OneDrive and documents back into a SharePoint library. So the usual permission set is read and write across the whole tenant, not read only.
The exact permissions vary by vendor and by which workloads you protect. Treat the table below as the shape to look for in your own tenant, not as any specific vendor's list. Help Net Security describes the app in the October incident as holding broad permissions to read and write email, OneDrive, SharePoint and Teams chats without a user signing in, without listing the permission names.
| Workload | Permission patterns you are likely to see | What it lets the app do | Why backup asks for it |
|---|---|---|---|
| Exchange Online mail | Mail.ReadWrite, or full_access_as_app (shown in Exchange RBAC as EWS.AccessAsApp) | Read and change mail in every mailbox; the EWS role gives full access to all mailboxes | Read for backup, write for restore |
| Calendars and contacts | Calendars.ReadWrite, Contacts.ReadWrite | Read and change every calendar and contact list | Same |
| OneDrive and SharePoint | Files.ReadWrite.All, Sites.ReadWrite.All, sometimes Sites.FullControl.All | Read and write any file or site in the tenant | Back up and restore documents, versions and permissions |
| Teams | Channel and chat message read permissions, plus Teams and group read | Read chats and channel messages across the tenant | Back up conversations |
| Directory | User.Read.All, Group.Read.All, sometimes Directory.Read.All | Enumerate every user and group | Know which mailboxes and sites exist |
| Management add ons | Directory roles such as Exchange Administrator, or role management permissions | Change configuration, not only data | Some vendors bundle tenant management with backup |
The last row is the one to watch. Reading data is the job; changing directory roles or adding credentials is a different class of power. Help Net Security reports a security firm's finding that Cloud Management apps granted themselves admin roles, mostly Exchange Administrator, in about 50 monitored organizations, a pattern that matched the vendor's own automation but that the vendor had not confirmed. An app that can assign roles can become more powerful than its consent screen suggested.
Delegated and application permissions are not the same risk
| Delegated permissions | Application permissions | |
|---|---|---|
| Who is acting | The app, on behalf of a signed in user | The app alone, no user |
| Limit on access | Never more than the signed in user can reach | Everything the permission covers, tenant wide |
| Who can consent | Users for their own data (if allowed), admins for everyone | Only an admin |
| What consent creates in Graph | An oAuth2PermissionGrant | An appRoleAssignment |
| Example from Microsoft docs | Files.Read.All delegated reads only files the user can access | Files.Read.All application reads any file in the tenant |
| Typical for backup | Rare | Normal |
The table follows Microsoft's comparison. A backup app's reach does not depend on any person's rights, MFA or sign-in risk, only on what an admin consented to.
What is an application identity, and why is it a durable credential?
When you register an app in Entra ID you create an application object in the home tenant. Microsoft describes it as the "template or blueprint" for the app. Every tenant that uses the app gets its own service principal, which Microsoft calls the "local representation" of the app in that tenant. For a multitenant app, a service principal "is created in each tenant where a user from that tenant has consented to its use."
So when your admin clicked through the backup vendor's onboarding and granted admin consent, three things happened:
- A service principal for the vendor's app was created in your tenant.
- The application permissions the admin approved were attached to that service principal as app role assignments.
- The vendor kept the credential, a client secret or certificate on its application object, in its own tenant.
That third point is why these identities are durable. Your password policies, MFA and sign-in risk rules do not apply to the vendor's certificate. Microsoft's Conditional Access documentation notes that workload identities "can't perform multifactor authentication" and "often have no formal lifecycle process."
- It outlives the people involved. The admin who consented in 2021 may be gone. The consent stays until someone revokes it.
- It is one key for many tenants. Help Net Security, citing a security firm's analysis, reports that the stolen credential worked in every organization that had granted the app access.
- You cannot rotate it. You can disable your service principal or revoke its permissions. Only the vendor can change its certificate.
How do you list every third-party app with tenant wide access?
You need three answers per app: who owns it, what application permissions it holds, and whether it holds any directory role. The admin center gives you a view per app. PowerShell gives you the whole tenant in one file.
In the Microsoft Entra admin center
- Sign in as at least a Cloud Application Administrator.
- Go to Entra ID, then Enterprise apps, then All applications.
- Set the Application type filter to show enterprise applications, and sort or filter so you can see apps not owned by your organization.
- Open an app, then select Permissions. The Admin consent tab shows permissions granted for the whole organization. The User consent tab shows what individual users granted.
- Select a permission to open Permission Details. From the Admin consent tab you can revoke organization wide grants. Microsoft notes you cannot revoke user consent grants in the portal; use Graph or PowerShell for those.
This is fine for five apps. Most tenants have dozens or hundreds, so script it.
With Microsoft Graph PowerShell: build the inventory
Install the Microsoft Graph PowerShell SDK, then connect with read scopes. Read only scopes are enough for everything in this section.
Install-Module Microsoft.Graph -Scope CurrentUser
Connect-MgGraph -Scopes "Application.Read.All","Directory.Read.All",`
"DelegatedPermissionGrant.Read.All","RoleManagement.Read.Directory" -NoWelcome
$tenantId = (Get-MgContext).TenantId
# Every application service principal in the tenant
$sps = Get-MgServicePrincipal -All -Filter "servicePrincipalType eq 'Application'" `
-Property Id,AppId,DisplayName,AppOwnerOrganizationId,AccountEnabled,PublisherName,VerifiedPublisher
# Owned by another organization, excluding Microsoft's own first party tenants
$microsoftTenants = @('f8cdef31-a31e-4b4a-93e4-5f571e91255a','72f988bf-86f1-41af-91ab-2d7cd011db47')
$external = $sps | Where-Object {
$_.AppOwnerOrganizationId -and
$_.AppOwnerOrganizationId -ne $tenantId -and
$microsoftTenants -notcontains $_.AppOwnerOrganizationId
}
"{0} third-party service principals" -f $external.Count
Now resolve each app's application permissions into readable names. An app role assignment stores a resource ID and a role GUID; the role's name lives on the resource's service principal (for example, Microsoft Graph or Office 365 Exchange Online).
$resourceCache = @{}
function Resolve-AppRole {
param($ResourceId, $AppRoleId)
if (-not $resourceCache.ContainsKey($ResourceId)) {
$resourceCache[$ResourceId] = Get-MgServicePrincipal -ServicePrincipalId $ResourceId -Property Id,DisplayName,AppRoles
}
$res = $resourceCache[$ResourceId]
$role = $res.AppRoles | Where-Object Id -eq $AppRoleId
"{0}: {1}" -f $res.DisplayName, $role.Value
}
$report = foreach ($sp in $external) {
$appPerms = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -All |
ForEach-Object { Resolve-AppRole -ResourceId $_.ResourceId -AppRoleId $_.AppRoleId }
$delegated = Get-MgOauth2PermissionGrant -All -Filter "clientId eq '$($sp.Id)'" |
ForEach-Object { "{0}: {1}" -f $_.ConsentType, $_.Scope.Trim() }
$roles = Get-MgRoleManagementDirectoryRoleAssignment -All -Filter "principalId eq '$($sp.Id)'" |
ForEach-Object { (Get-MgRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $_.RoleDefinitionId).DisplayName }
[pscustomobject]@{
DisplayName = $sp.DisplayName
AppId = $sp.AppId
ServicePrincipalId = $sp.Id
Enabled = $sp.AccountEnabled
Publisher = $sp.PublisherName
VerifiedPublisher = $sp.VerifiedPublisher.DisplayName
ApplicationPermissions = ($appPerms -join '; ')
DelegatedGrants = ($delegated -join ' | ')
DirectoryRoles = ($roles -join '; ')
}
}
$report | Sort-Object DisplayName |
Export-Csv .\third-party-app-access.csv -NoTypeInformation
Open the CSV and sort by the ApplicationPermissions and DirectoryRoles columns. Anything containing ReadWrite.All, FullControl.All, full_access_as_app, Mail.Send, AppRoleAssignment.ReadWrite.All, Application.ReadWrite.All or RoleManagement.ReadWrite.Directory, or holding any directory role, goes on your short list. Those are the apps whose compromise would look like a compromise of your tenant.
In the DelegatedGrants column, AllPrincipals means an admin consented for everyone; Principal means one user consented for themselves.
The two excluded tenant IDs are the ones Microsoft uses for its own first party apps; check your output rather than trusting the filter. Microsoft also reminds admins that consent is not the only authorization system: Entra roles, Exchange RBAC and Teams resource specific consent can grant access too, which is why the script checks directory roles.
Match on App ID, not display name
ConnectWise's advisory tells partners to match disabled apps by Application ID and record the local Object ID, because older installs may carry different display names. That applies to any vendor. Keep both the AppId and the ServicePrincipalId in your inventory.
What happens on your side when a vendor's app identity is compromised?
The attacker signs in as the vendor's app, gets a token for your tenant and uses whatever permissions your service principal holds. To your logs it looks like the backup service doing its job, which is why these incidents can run for days.
What the vendor can fix, and what only you can fix
| Action | Vendor can do it | Only you can do it |
|---|---|---|
| Revoke or rotate its application credential | Yes | No |
| Disable its application globally so no tenant can get new tokens | Yes, by disabling or deleting its app or credentials | No |
| Disable the service principal in your tenant | No | Yes |
| Revoke the permissions your admin granted | No | Yes |
| Remove credentials the attacker added to other apps in your tenant | No | Yes |
| Remove directory roles, mailbox rules or forwarding the attacker created | No | Yes |
| Read your sign-in and audit logs | No | Yes |
| Tell you which data the attacker read | Usually no, and the logs may not show every read | Partly, through your logs |
ConnectWise's advisory says this directly: disabling its applications prevents new authentication but does not reverse changes already made inside a tenant, and each organization must find and remove attacker created credentials, roles or access. Help Net Security adds a caution from the security firm it cites: Microsoft does not log some application data reads, so the absence of evidence in your logs is not proof nothing was read.
Your first 24 hours: a step by step response
Run these in order. Steps 1 and 2 preserve evidence; steps 3 onward contain and clean.
1. Export logs before you change anything. Disabling apps and deleting objects creates noise and, for some log types, your retention window is short. Export directory audit logs and service principal sign-in logs for at least the period the vendor names. ConnectWise asked partners to review from 13 October.
Connect-MgGraph -Scopes "AuditLog.Read.All","Directory.Read.All" -NoWelcome
$since = (Get-Date "2026-10-13T00:00:00Z").ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
Get-MgAuditLogDirectoryAudit -All -Filter "activityDateTime ge $since" |
Select-Object ActivityDateTime, ActivityDisplayName, Category, Result,
@{n='ActorUser';e={$_.InitiatedBy.User.UserPrincipalName}},
@{n='ActorApp'; e={$_.InitiatedBy.App.DisplayName}},
@{n='Target'; e={($_.TargetResources | ForEach-Object DisplayName) -join '; '}} |
Export-Csv .\directory-audit-since-1013.csv -NoTypeInformation
Service principal sign-ins are separate from the default user sign-in view. In the admin center go to Entra ID, then Monitoring and health, then Sign-in logs, then Service principal sign-ins, and filter by the vendor's App ID. Through Graph, the beta sign-ins endpoint accepts a filter on sign-in event type:
$appId = "<vendor-app-id>"
$uri = "https://graph.microsoft.com/beta/auditLogs/signIns?`$filter=signInEventTypes/any(t: t eq 'servicePrincipal') and appId eq '$appId' and createdDateTime ge $since"
$result = Invoke-MgGraphRequest -Method GET -Uri $uri
$result.value | Select-Object createdDateTime, ipAddress, resourceDisplayName, status |
Format-Table -AutoSize
Microsoft's playbook says to look for unexpected locations, bursts of failures, odd timestamps and changes in frequency, and to check the resource each token was issued for.
2. Pull the specific audit activities that indicate persistence. Microsoft's compromised application playbook names the activities to filter on.
$activities = @(
"Consent to application",
"Add app role assignment to service principal",
"Add delegated permission grant",
"Add service principal credentials",
"Add owner to application",
"Add owner to service principal",
"Add member to role"
)
foreach ($a in $activities) {
Get-MgAuditLogDirectoryAudit -All -Filter "activityDisplayName eq '$a' and activityDateTime ge $since" |
Select-Object ActivityDateTime, ActivityDisplayName,
@{n='ActorUser';e={$_.InitiatedBy.User.UserPrincipalName}},
@{n='ActorApp'; e={$_.InitiatedBy.App.DisplayName}},
@{n='Target'; e={$_.TargetResources[0].DisplayName}}
}
# Credential changes on app registrations
Get-MgAuditLogDirectoryAudit -All -Filter "startswith(activityDisplayName,'Update application') and activityDateTime ge $since" |
Select-Object ActivityDateTime, ActivityDisplayName,
@{n='ActorApp';e={$_.InitiatedBy.App.DisplayName}},
@{n='Target'; e={$_.TargetResources[0].DisplayName}}
Pay attention to rows where ActorApp is the vendor's app. An app acting as the initiator of a role assignment or a credential change is the pattern Help Net Security describes, including one case where an app made itself Global Administrator and added credentials to other apps that stayed valid until 2028.
3. Find credentials added to any app or service principal since the window opened. Attackers who reach a tenant with enough rights often add their own secret to an existing, trusted app so they keep access after the original door closes.
$cutoff = Get-Date "2026-10-13T00:00:00Z"
Get-MgApplication -All -Property Id,AppId,DisplayName,PasswordCredentials,KeyCredentials |
ForEach-Object {
$app = $_
@($app.PasswordCredentials) + @($app.KeyCredentials) |
Where-Object { $_ -and $_.StartDateTime -ge $cutoff } |
ForEach-Object { [pscustomobject]@{ Object='Application'; Name=$app.DisplayName; AppId=$app.AppId; KeyId=$_.KeyId; Start=$_.StartDateTime; End=$_.EndDateTime } }
}
Get-MgServicePrincipal -All -Property Id,AppId,DisplayName,PasswordCredentials,KeyCredentials |
ForEach-Object {
$sp = $_
@($sp.PasswordCredentials) + @($sp.KeyCredentials) |
Where-Object { $_ -and $_.StartDateTime -ge $cutoff } |
ForEach-Object { [pscustomobject]@{ Object='ServicePrincipal'; Name=$sp.DisplayName; AppId=$sp.AppId; KeyId=$_.KeyId; Start=$_.StartDateTime; End=$_.EndDateTime } }
}
Every row needs an owner who can say "yes, I added that." Rows nobody claims are incidents of their own.
4. Disable the vendor's service principal in your tenant. Disable, do not delete. Disabling keeps the object, its permissions and its history for the investigation and for a clean reconnection later. Microsoft's playbook recommends disabling sign-in first, and the security firm cited by Help Net Security gave the same advice.
Connect-MgGraph -Scopes "Application.ReadWrite.All" -NoWelcome
$appId = "<vendor-app-id>"
$sp = Get-MgServicePrincipal -Filter "appId eq '$appId'"
Update-MgServicePrincipal -ServicePrincipalId $sp.Id -BodyParameter @{ accountEnabled = $false }
In the portal the same switch is Enabled for users to sign in set to No on the enterprise app's Properties page. Then watch the audit log for "Update service principal" with account enabled changing back to true, which Microsoft lists as the event to monitor.
5. Revoke the permissions if the business can live without the service for a while. This is a bigger step than disabling, because reconnecting will need a fresh admin consent. Microsoft's documented script removes delegated grants and application permissions for one service principal:
Connect-MgGraph -Scopes "Application.ReadWrite.All","Directory.ReadWrite.All",`
"DelegatedPermissionGrant.ReadWrite.All","AppRoleAssignment.ReadWrite.All"
$sp = Get-MgServicePrincipal -ServicePrincipalId "<service-principal-object-id>"
Get-MgOauth2PermissionGrant -All | Where-Object { $_.ClientId -eq $sp.Id } |
ForEach-Object { Remove-MgOauth2PermissionGrant -OAuth2PermissionGrantId $_.Id }
Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -All |
Where-Object { $_.PrincipalType -eq "ServicePrincipal" } |
ForEach-Object { Remove-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $sp.Id -AppRoleAssignmentId $_.Id }
6. Remove any directory roles the app holds. Use the role assignment IDs from the inventory script, then remove them:
Get-MgRoleManagementDirectoryRoleAssignment -All -Filter "principalId eq '$($sp.Id)'" |
ForEach-Object { Remove-MgRoleManagementDirectoryRoleAssignment -UnifiedRoleAssignmentId $_.Id }
7. Check mailboxes for rules and forwarding. ConnectWise's advisory lists mailbox rules and forwarding among the items to review. In Exchange Online PowerShell:
Connect-ExchangeOnline
Get-Mailbox -ResultSize Unlimited |
Where-Object { $_.ForwardingSmtpAddress -or $_.ForwardingAddress } |
Select-Object UserPrincipalName, ForwardingSmtpAddress, ForwardingAddress, DeliverToMailboxAndForward
Get-Mailbox -ResultSize Unlimited | ForEach-Object {
Get-InboxRule -Mailbox $_.UserPrincipalName |
Where-Object { $_.ForwardTo -or $_.RedirectTo -or $_.ForwardAsAttachmentTo -or $_.DeleteMessage }
} | Select-Object MailboxOwnerId, Name, ForwardTo, RedirectTo, DeleteMessage
On a large tenant, narrow the second loop to mailboxes that matter most, or run it in batches.
8. Review everything else the advisory names. Federation trusts, conditional access changes, new owners on apps and other identities modified during the suspicious window. If you are an MSP, the advisory asks you to pass the guidance to the administrators of each customer tenant you manage, since the cleanup has to happen in each one.
9. Record what you decided and why, for your incident record, any notices and the vendor review.
Can you reduce scope with application access policies or per mailbox restrictions?
Partly. Microsoft offers several ways to narrow an app's reach. Each comes with a catch, and none of them works unless the vendor's product supports it.
Exchange Online: RBAC for Applications
Exchange Online lets an admin grant mail, calendar and contact permissions to an app with a resource scope, so the app reaches only a defined set of mailboxes. Microsoft says this feature "replaces Application Access Policies," the older mechanism many admins still know as New-ApplicationAccessPolicy.
The steps, from Microsoft's documentation:
Connect-ExchangeOnline
# 1. Point Exchange at the existing Entra service principal (use Enterprise apps IDs, not App registrations)
New-ServicePrincipal -AppId "<app-id>" -ObjectId "<service-principal-object-id>" -DisplayName "Backup app"
# 2. Define the mailboxes in scope
New-ManagementScope -Name "Backed up mailboxes" -RecipientRestrictionFilter "CustomAttribute1 -eq 'backup'"
# 3. Assign a scoped application role
New-ManagementRoleAssignment -App "<service-principal-object-id>" -Role "Application Mail.Read" -CustomResourceScope "Backed up mailboxes"
# 4. Test against a specific mailbox
Test-ServicePrincipalAuthorization -Identity "Backup app" -Resource "someone@contoso.com" | Format-Table
The catch is in Microsoft's FAQ. Exchange RBAC grants are added to anything granted in Entra ID. If the app still holds tenant wide Mail.Read from admin consent, the scoped grant achieves nothing; the union is everything. You have to remove the unscoped Entra grant for scoping to take effect. Changes can also take between 30 minutes and 2 hours to apply because of caching.
The other catch is specific to backup: scoping the app to fewer mailboxes means fewer mailboxes are protected. Scoping helps when a few mailboxes, perhaps board mail, are protected another way and you want them out of the third-party service entirely.
SharePoint and OneDrive: Selected scopes
Microsoft Graph has a family of Selected permissions: Sites.Selected, Lists.SelectedOperations.Selected, ListItems.SelectedOperations.Selected and Files.SelectedOperations.Selected. An app consented for one of these starts with no access. An admin then grants access to each named site, list or file with a role of read, write, owner or full control:
Connect-MgGraph -Scopes "Sites.FullControl.All"
$params = @{
roles = @("read")
grantedToIdentities = @(@{ application = @{ id = "<app-id>"; displayName = "Backup app" } })
}
New-MgSitePermission -SiteId "<site-id>" -BodyParameter $params
This suits an integration that needs a handful of sites, rarely a whole tenant backup, since every new site needs its own grant. Ask the vendor whether it supports Selected scopes.
Conditional Access for workload identities: not for vendor apps
Many admins assume they can restrict the backup app to the vendor's IP ranges with Conditional Access. Microsoft's documentation says otherwise: policy "can be applied to single tenant service principals that are registered in your tenant," and "third-party SaaS applications, including multitenant apps, are not covered." It also requires Workload Identities Premium licensing. So this control protects your own automation, not your backup vendor's app.
Tenant settings that stop the next unwanted app
These do not shrink an existing backup app's access, but they stop new apps from arriving the way many unwanted ones do.
- User consent. Microsoft recommends allowing user consent only for apps from verified publishers. In the admin center: Enterprise apps, then Consent and permissions, then User consent settings. Read the current setting first:
Connect-MgGraph -Scopes "Policy.Read.All"
(Get-MgPolicyAuthorizationPolicy).DefaultUserRolePermissions.PermissionGrantPoliciesAssigned
If the output contains managePermissionGrantsForSelf.microsoft-user-default-legacy, any user can consent to any permission that does not need an admin. Microsoft's guidance is to keep the existing managePermissionGrantsForOwnedResource.* entries when you change this, so you do not break developer consent for apps they own.
- Admin consent workflow. With user consent restricted, turn on the admin consent workflow so users can request an app and an admin reviews it, rather than users finding workarounds.
- Remember that changes are forward only. Microsoft notes that changing consent settings "only affect future consent operations." Existing grants stay until you revoke them, which is why the inventory comes first.
For the related problem of attackers tricking users into approving apps, see device code phishing: the OAuth flow you should disable.
Decision table: which control fits
| Goal | Control | Works on third-party backup app? | Main limit |
|---|---|---|---|
| Know what every app can do | Graph PowerShell inventory | Yes | Point in time; rerun on a schedule |
| Stop a compromised app now | Disable service principal | Yes | Existing tokens live until expiry; changes not reversed |
| Remove access entirely | Revoke grants or delete service principal | Yes | Reconnection needs fresh admin consent |
| Limit mail access to some mailboxes | Exchange RBAC for Applications | Only if you remove the Entra grant and the vendor supports it | Fewer mailboxes backed up |
| Limit file access to some sites | Sites.Selected and related scopes | Only if the vendor supports it | Per site grants to maintain |
| Restrict by IP or risk | Conditional Access for workload identities | No | Single tenant apps only; extra licence |
| Stop unvetted new apps | User consent settings, admin consent workflow | Prevents future cases | Does not touch existing grants |
Which questions should you ask a backup vendor before and after an incident?
Ask in writing, keep the answers, and review them on a schedule. These questions turn the mechanics above into vendor due diligence.
Before you sign, or at the next renewal
- Which exact permissions does your app request, per workload, and why? Ask for permission names and compare them with your inventory.
- Do you need any directory roles or role management permissions? If so, for which feature, and can it be switched off?
- Are backup and tenant management separate apps? Then you can grant management only where you use it.
- Do you support scoped access through Exchange RBAC for Applications or
Sites.Selected? - What credential does your app use, where is it stored and how often is it rotated? Is it shared across every customer, or split by customer or region?
- How fast, and through which channel, will you notify us if your app identity is suspected compromised?
- Can we export our backups in a usable format, and how long does a full export take?
- What complementary user entity controls does your SOC 2 report list? Those are the controls you are expected to run.
After an incident
- Which App IDs were affected, over what window, and how was the credential exposed?
- Are all affected credentials revoked, and are earlier tokens now invalid?
- Is our tenant among those accessed, and were stored archives touched?
- Which actions did your own automation take in our tenant during the window, so we can tell them apart from the attacker's?
- What will reconnection require, and will you share a written post incident report?
How do SOC 2 and ISO 27001 treat a vendor with this level of access?
Both frameworks expect you to know which suppliers can reach your data, to assess them in proportion to that access and to keep evidence that you did.
SOC 2. The AICPA's Trust Services Criteria include a common criterion on vendor risk, CC9.2, widely summarized as requiring that the entity assesses and manages risks associated with vendors and business partners. The logical access criteria in the CC6 series also apply, because a third-party app with tenant wide permissions is a logical access path to your systems. In practice auditors look for a vendor inventory, a risk rating per vendor, a review on a schedule (often annual, more often for high risk), the vendor's own SOC 2 report or equivalent, and evidence that you reviewed it.
Two parts of a vendor's SOC 2 report deserve more attention. Complementary user entity controls (CUECs) are controls the vendor assumes you operate, such as restricting consent and reviewing app permissions; if you do not run them, the clean report does not cover you. Subservice organizations carved out of the report, such as a hosting or key storage provider, need a separate look.
ISO/IEC 27001:2022. Annex A has a group of supplier controls, 5.19 to 5.22, covering information security in supplier relationships, security requirements in supplier agreements, the ICT supply chain, and monitoring and review of supplier services. Control 5.23 covers cloud services. Control 8.13 covers information backup. A Microsoft 365 backup vendor touches all of them. An auditor will expect to see the vendor in your supplier register, a risk assessment that reflects the access the app holds, contract terms that address security and incident notice, and evidence of periodic review. Read the standard itself for the normative wording; summaries vary.
A strong evidence pack for a high access SaaS vendor holds a dated inventory export of the app's permissions, a risk rating that cites them, the vendor's SOC 2 report with your review notes and CUEC mapping, questionnaire answers, the incident notice clause from the contract, and a periodic access review record. For more on reviews that change something rather than rubber stamp it, see access reviews that actually revoke something.
Should you keep a second, independent copy of critical data?
For data you cannot afford to lose, yes. The October incident shows why in a way most backup plans do not model: the backup service was suspended across all users, scheduled backups stopped, and the Kaseya roundup reports that access to backup archives and restore capabilities was unavailable while the vendor investigated. Nothing in the archives had to be damaged for customers to lose the ability to restore for a while.
A second copy is only independent if it fails differently:
- Different identity, so a compromise or suspension of one app does not touch the other.
- Different storage and administrative domain. A second copy at the same vendor is a replica.
- Immutable or offline for a period, so write access through one path cannot delete the other.
- Tested restores. Restore a mailbox, a OneDrive and a SharePoint library on a schedule and time it.
- Scoped to what matters, such as legal, finance, executive mail and key project sites.
Microsoft 365 retention features keep content inside the tenant; treat them as a layer, not as the second copy.
There is a trade off. Two backup vendors each holding tenant wide ReadWrite.All means two keys that open everything. If you add a second path, prefer read only permissions where possible, a separate credential model and the narrowest scope that covers the critical set.
Common mistakes
- Treating "we disabled our app" as the end. It stops new sign-ins, not the credentials, roles, rules or forwarding already created, and earlier tokens can live until expiry.
- Deleting the service principal first. You lose investigation context. Disable, investigate, then decide.
- Looking only at user sign-in logs. App activity sits under Service principal sign-ins, a separate view.
- Matching apps by display name. Use the App ID.
- Adding Exchange scoping without removing the Entra grant. The two are additive, so the tenant wide grant stays in force.
- Relying on Conditional Access to fence in a vendor app. It does not cover third-party multitenant apps.
- Assuming no log entry means no access. Some application data reads are not logged.
- Rating all SaaS vendors the same. A survey tool with
User.Readand a backup tool withFiles.ReadWrite.Allare different risks. - Filing the vendor's SOC 2 report without reading the CUECs. Those are your controls.
- Keeping a second copy under the same identity. That is one copy twice.
Where Safeguard fits
Safeguard is not a Microsoft 365 configuration tool. It does not change Entra ID settings, disable service principals or read your sign-in logs, and it would not have prevented a vendor's credential from being stolen. The Graph PowerShell work above stays in Microsoft's tools.
Where Safeguard helps is the record keeping and follow through, inside its generally available compliance and GRC suite:
- Vendors. Keep each SaaS vendor in the vendor register with a note of the privileged access it holds, and store its SOC 2 report against the record, marked reviewed.
- Questionnaires and risks. Send the questions above as a vendor questionnaire, and record "backup app holds tenant wide access" as a risk with an owner and a treatment.
- Access reviews and evidence. Schedule periodic reviews and attach the dated inventory export and review record as evidence mapped to SOC 2 and ISO 27001 vendor controls.
That turns a one time scramble into a review you repeat, with the evidence in one place when an auditor asks.
Fix it without waiting for upstream
A backup vendor's app identity is a supplier risk you manage through permissions, contracts and reviews. The software you build carries the same kind of supplier risk in its open source dependencies and container images, and there the fix does not have to wait on someone else's schedule.
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.
3. Gold Registry: start from components that are already fixed
registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | The Gold scan GitHub Action in CI, plus Safeguard policies and gates |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch (early access) |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
FAQ
Can my Microsoft 365 backup provider read my email?
Technically, yes, if its app holds an application permission such as Mail.Read, Mail.ReadWrite or full_access_as_app. Those permissions let the app read every mailbox in scope without a user signed in. Whether the vendor's staff can view content depends on its own controls, which is a question for its SOC 2 report and your contract.
How do I see which apps have access to my Microsoft 365 tenant?
In the Microsoft Entra admin center, go to Enterprise apps, then All applications, and open each app's Permissions page. For the full picture, run the Graph PowerShell inventory in this post, which lists every third-party service principal with its application permissions, delegated grants and directory roles.
Does disabling an enterprise app revoke its access immediately?
It blocks new token requests. Tokens issued before you disabled it can keep working until they expire, and anything the app already changed stays changed. Disable first, then review credentials, roles and mailbox rules.
Can I restrict a backup app to certain mailboxes?
Yes, with Exchange Online RBAC for Applications, which replaces Application Access Policies. You must also remove the tenant wide Entra grant, since the two are additive, and the vendor must support it. Remember that excluded mailboxes are no longer backed up by that service.
Can I use Conditional Access to block a vendor app from unknown IP addresses?
No. Microsoft's documentation says Conditional Access for workload identities applies to single tenant service principals registered in your tenant and does not cover third-party SaaS or multitenant apps.
Do I need a second backup if I already pay for a Microsoft 365 backup service?
For critical data, a second independent copy is sensible. In October 2026 a backup service was suspended across all users during an investigation, which paused backups and restores. Make the second copy use a different identity and storage, and test restores from it.
What does SOC 2 require for a vendor with access to our Microsoft 365?
SOC 2's vendor criterion, CC9.2, expects you to assess and manage vendor risk. In practice that means an inventory, a risk rating that reflects the access, review of the vendor's SOC 2 report including its complementary user entity controls, periodic review and evidence of each step.
How often should we review third-party app permissions?
At least quarterly for apps with tenant wide application permissions or directory roles, and immediately when a vendor reports an incident, changes its permission request or is acquired. Rerun the inventory script and compare it with the last export.
See how Safeguard would help
Safeguard does not change Entra ID settings, but the habit this post argues for, granting a connected app only what it needs, applies to the AI assistants your team connects too. This demo shows Claude connecting to the Safeguard MCP server with OAuth and choosing which Safeguard tools Claude can use.
Click through it at your own pace, or open it full screen.
The runner demo shows setting up the Safeguard runner on your own machine, approving it with its device code and then scanning from the terminal. It is a useful pattern when you want scanning to happen inside your environment instead of handing a third party standing access to your code.
Click through it at your own pace, or open it full screen.
Finally, a real Safeguard CLI session: asked to fix a lodash CVE, it reads the finding and advisory, asks before each command, edits package.json to lodash 4.17.21, runs npm install and npm test with approval and pushes nothing. Approval at each step is the opposite of a standing, tenant wide grant.
Click through it at your own pace, or open it full screen.
To try it yourself, download Safeguard and read the CLI documentation.
Quick check
A backup vendor says it has disabled its compromised app identity. Why is your tenant not automatically safe?
Disabling stops new sign-ins, but tokens issued earlier can keep working until they expire, and any credentials, directory roles, mailbox rules or forwarding the attacker created in your tenant stay in place. Only you can find and remove those.
You add an Exchange RBAC for Applications grant that scopes the backup app's Mail.Read to 200 mailboxes. The app can still read every mailbox. What did you miss?
The tenant wide Mail.Read application permission granted through Entra ID admin consent is still there. Exchange RBAC grants are added to Entra grants, so you must remove the unscoped Entra grant for the scope to take effect.
Sources
- ConnectWise Trust Center: advisories (Cloud Backup incident)
- Help Net Security: ConnectWise suspends Cloud Backup service after attackers abuse its Microsoft 365 access
- Kaseya: The Week in Breach News, 21 October 2026
- The Hacker News: Weekly Recap, October 2026
- Microsoft Learn: Apps and service principals in Microsoft Entra ID
- Microsoft Learn: Overview of permissions and consent in the Microsoft identity platform
- Microsoft Learn: Review permissions granted to enterprise applications
- Microsoft Learn: Configure how users consent to applications
- Microsoft Learn: Compromised and malicious applications investigation
- Microsoft Learn: Conditional Access for workload identities
- Microsoft Learn: Role Based Access Control for Applications in Exchange Online
- Microsoft Learn: Overview of Selected permissions in OneDrive and SharePoint
- AICPA: 2017 Trust Services Criteria (revised points of focus, 2022)
Last reviewed: 23 October 2026. The vendor incident used as an example is still developing; check the vendor's advisory for the latest status.