During the ConnectWise Cloud Backup incident on 15 October 2026, Huntress found that in one partner tenant a ConnectWise Cloud Management app granted itself Global Administrator and then added new client secrets, valid until 2028, to two other applications. One of them was Huntress's own app. A client secret on someone else's app is quiet persistence: it survives password resets, session revocation and even disabling the app that planted it.
Microsoft Entra has a control built for exactly this: app management policies that block new password credentials on applications and service principals. Huntress lists them among its recommendations. This guide shows how to measure your exposure, turn the policy on and handle the apps that still need secrets.
What's affected
Any Entra tenant where the tenant default app management policy is off, which is the default state. Per Microsoft Graph documentation, the tenantAppManagementPolicy object "always exists and is disabled by default."
Two things make secrets attractive to an attacker. Anyone with enough directory privilege can add one to an app they don't own. And once added, it works from anywhere until it expires, which the attacker gets to choose.
One limit to keep in mind from the start: Microsoft says neither the tenant default nor per-app policies block token issuance for existing applications. An app that already violates the policy keeps working. Only the create or update operation that breaks the rule is blocked. So the policy stops new secrets, and you still have to clean up the old ones.
How to check if you're exposed
Connect with Microsoft Graph PowerShell and read the current policy:
Connect-MgGraph -Scopes "Policy.Read.All","Application.Read.All"
Import-Module Microsoft.Graph.Identity.SignIns
Get-MgPolicyDefaultAppManagementPolicy | Format-List IsEnabled, ApplicationRestrictions, ServicePrincipalRestrictions
If IsEnabled is false, nothing is enforced.
Next, count who actually relies on secrets. Applications you own and service principals of apps from other tenants are separate objects with separate restrictions, so check both.
$apps = Get-MgApplication -All -Property "id,displayName,appId,passwordCredentials"
$apps | Where-Object { $_.PasswordCredentials.Count -gt 0 } |
Select-Object DisplayName, AppId, @{n="Secrets";e={$_.PasswordCredentials.Count}}
$sps = Get-MgServicePrincipal -All -Property "id,displayName,appId,passwordCredentials"
$sps | Where-Object { $_.PasswordCredentials.Count -gt 0 } |
Select-Object DisplayName, AppId, @{n="Secrets";e={$_.PasswordCredentials.Count}}
Then look for long-lived secrets. The passwordCredential resource exposes startDateTime and endDateTime, so this flags anything valid for more than a year:
foreach ($o in @($apps) + @($sps)) {
foreach ($c in $o.PasswordCredentials) {
if (($c.EndDateTime - $c.StartDateTime).TotalDays -gt 365) {
[pscustomobject]@{ Object = $o.DisplayName; AppId = $o.AppId; KeyId = $c.KeyId; Hint = $c.Hint; Expires = $c.EndDateTime }
}
}
}
Every row is a credential an attacker would love to have created. Any secret on a service principal that nobody on your team recognizes deserves a closer look now.
What to do now
-
Fix the apps that need secrets first. Move them to certificates or workload identity federation before enforcement, or plan explicit exemptions for them in step 4.
-
Turn on the restriction in the admin center. Microsoft's how-to: Entra ID, Enterprise apps, Application policies, select Block password addition, set the status to On with Applies to set to All applications, then Save. In the portal this setting combines the
passwordAdditionandsymmetricKeyAdditionrestrictions. -
Or do it through Graph so it's in source control. The documented update call is
PATCH /policies/defaultAppManagementPolicy, which accepts restrictions for bothapplicationRestrictionsandservicePrincipalRestrictions. Include any restrictions already present, because omitted entries can be disabled by accident.Connect-MgGraph -Scopes "Policy.ReadWrite.ApplicationConfiguration" $block = @( @{ restrictionType = "passwordAddition"; maxLifetime = $null; restrictForAppsCreatedAfterDateTime = [System.DateTime]::Parse("2015-01-01T00:00:00Z") } @{ restrictionType = "symmetricKeyAddition"; maxLifetime = $null; restrictForAppsCreatedAfterDateTime = [System.DateTime]::Parse("2015-01-01T00:00:00Z") } ) $params = @{ isEnabled = $true applicationRestrictions = @{ passwordCredentials = $block } servicePrincipalRestrictions = @{ passwordCredentials = $block } } Update-MgPolicyDefaultAppManagementPolicy -BodyParameter $paramsThe
restrictForAppsCreatedAfterDateTimevalue controls which objects are covered. Microsoft notes that service principals with a null creation date are treated as created on 1 January 2019, so an earlier date covers them too. -
Exempt narrowly. For a specific app, create a custom policy under
/policies/appManagementPolicieswith the restriction set todisabledand assign it to that app. Only one custom policy can be assigned per app or service principal. For an automation that creates apps, Microsoft documents caller exemptions through custom security attributes referenced inexcludeActors. -
Cap certificate lifetimes too. The
asymmetricKeyLifetimerestriction underkeyCredentialstakes an ISO 8601 duration, so a planted certificate can't be valid for years. -
Delete the long-lived secrets you found, after rotating the apps that legitimately used them.
Why it matters
Incident response tends to focus on the identity that was abused. In the ConnectWise case, that was the backup app. The secrets it added to other apps are what let an attacker come back after that app is disabled.
Policy is cheaper than hunting. Blocking new secrets tenant-wide means a future attacker with directory privileges has to use a noisier path, and any legitimate need for a secret becomes a documented exception instead of a default.
Try it yourself
Run the long-lived secret query from the check section in a test tenant or your production tenant. Sort by Expires and pick the three secrets that live longest. For each one, write down the owner, what it authenticates to and whether a certificate or federated credential could replace it. That list is your rollout plan.
Click through it at your own pace, or open it full screen.
Quick check
Does enabling the policy break apps that already use client secrets?
No. Microsoft states the policies don't block token issuance for existing applications. They only block the create or update operation that violates the rule, such as adding a new secret.
Which restriction set covers apps from another tenant, like a vendor's backup tool?
servicePrincipalRestrictions. Restrictions under applicationRestrictions apply to application objects your tenant owns.
How do you let one app keep adding secrets while the rest are blocked?
Create a custom app management policy with that restriction disabled and assign it to the app. The custom policy takes precedence over the tenant default for that object.
Sources
- Huntress: Vendor credential enables unauthorized access
- Microsoft Graph: Application management policy API overview
- Microsoft Graph: Update tenantAppManagementPolicy
- Microsoft Graph: Get tenantAppManagementPolicy
- Microsoft Graph: passwordCredentialConfiguration resource
- Microsoft Graph: passwordCredential resource
- Microsoft Learn: Configure restrictions on how applications can be configured