Listen to this Post

Introduction:
Microsoft’s shift from classic Service Principal agents to modern Blueprint agents marks a fundamental transformation in cloud identity management, yet the transition introduces a dangerous security gap. As organizations race to adopt Microsoft Entra Agent ID following the May 1, 2026 general availability of Agent 365 licenses, tens of thousands of unmanaged “classic” agents remain exposed — lacking modern protections like Conditional Access, Identity Protection, or proper audit trails. A public GitHub script that audits and reports on these agents inadvertently revealed the attack surface: every classic agent is a potential backdoor waiting to be exploited.
Learning Objectives:
- Identify and inventory all classic Service Principal agents in your Microsoft Entra tenant using PowerShell and Microsoft Graph API
- Execute the “buggy version” of Microsoft’s migration audit script to generate HTML and CSV reports of vulnerable agents
- Implement hardening controls, including conditional access policies for workload identities and credential elimination via managed identities
You Should Know:
- Audit Your Classic Agent Inventory Before Attackers Do
Classic agents are AI agents created as standard service principals or app registrations — for example, agents built in Copilot Studio before the Entra Agent ID platform was enabled. They appear in the Microsoft Entra Agent Registry with ‘Has Agent ID: No’ and cannot be protected by security features such as Identity Protection or Conditional Access. This creates a critical blind spot: these agents operate with full privileges but zero governance.
Microsoft has indicated a migration tool is planned, but in the meantime, manual auditing is essential. A public PowerShell script — the “buggy version” referenced in the original post — generates HTML and CSV reports that map your entire classic agent landscape. Here’s how to run the audit and interpret the results.
Step‑by‑step audit using the Microsoft Graph PowerShell module:
Install required modules
Install-Module Microsoft.Graph -Force -AllowClobber
Install-Module Microsoft.Entra.Beta -RequiredVersion 1.2.0 -Repository PSGallery -Force
Connect to Microsoft Graph with appropriate scopes
Connect-MgGraph -Scopes "Application.Read.All", "ServicePrincipal.Read.All", "AgentIdentityBlueprint.Read.All"
Retrieve all service principals (potential classic agents)
$allSPs = Get-MgServicePrincipal -All -Property "DisplayName,AppId,Id,CreatedDateTime,Tags"
Identify classic agents (those WITHOUT blueprint association)
$classicAgents = $allSPs | Where-Object {
$<em>.Tags -notcontains "BlueprintAssociated" -and
$</em>.DisplayName -match "agent|bot|copilot|ai|automation"
}
Export findings to CSV
$classicAgents | Select-Object DisplayName, AppId, Id, CreatedDateTime |
Export-Csv -Path "ClassicAgentInventory.csv" -NoTypeInformation
Generate HTML report
$html = $classicAgents | ConvertTo-Html - "Classic Agent Inventory" -Property DisplayName, AppId, Id, CreatedDateTime
$html | Out-File -FilePath "ClassicAgentReport.html"
Write-Host "Found $($classicAgents.Count) classic agents requiring migration" -ForegroundColor Yellow
What this does: The script connects to your Entra tenant, retrieves every service principal, filters for potential classic agents by examining tags and display name patterns, and produces both CSV and HTML reports. The “buggy version” referenced by Derk van der Woude creates detailed reports with color-coded risk indicators.
Critical detection — finding agents with privileged directory roles (post-patch awareness):
BASE="https://graph.microsoft.com"
roles="$(az rest -m GET --url "${BASE}/beta/roleManagement/directory/roleDefinitions?\$filter=isPrivileged eq true&\$select=id,displayName" -o json)"
u="${BASE}/beta/roleManagement/directory/roleAssignments?\$expand=principal(\$select=id,displayName)&\$top=999"
{
echo -e "SP_NAME\tSP_ID\tROLE"
echo -e "--\t\t-"
while :; do
j="$(az rest -m GET --url "$u" -o json 2>/dev/null)" || break
jq -r --argjson roles "$roles" '
($roles.value | map({key:.id, value:.displayName}) | from_entries) as $r |
.value[] |
select(.principal."@odata.type"=="microsoft.graph.servicePrincipal") |
select($r[.roleDefinitionId] != null) |
[.principal.displayName, (.principal.id // .principalId), $r[.roleDefinitionId]] |
@tsv
' <<<"$j"
u="$(jq -r '."@odata.nextLink"//empty' <<<"$j")"
[[ -z "$u" ]] && break
done | sort -t$'\t' -k1,1
} | column -t -s $'\t'
This Azure CLI + jq pipeline identifies service principals with dangerous directory roles — exactly what attackers target when they compromise Agent ID Administrator privileges.
- Modern Blueprint Agents Are Your Only Secure Path Forward
Modern agents are created through the Microsoft Entra Agent ID platform, each backed by an Agent Identity Blueprint. A blueprint serves four purposes: it acts as a template for consistent configuration, an identity that can provision agent identities, a credential container where all agent credentials are stored, and a management container for applying policies at scale. Building on a blueprint is the recommended path for new agents because it unlocks governed Work IQ tool access, Microsoft Purview data protection, Microsoft Defender threat monitoring, and Entra ID governance — making your agent a fully governed enterprise identity from day one.
Step‑by‑step creation of a secure Agent Identity Blueprint:
Connect with beta module for Agent ID support
Connect-MgGraph -Scopes "AgentIdentityBlueprint.ReadWrite.All", "Application.ReadWrite.All"
Create a new Agent Identity Blueprint
$blueprintParams = @{
DisplayName = "SecureSalesAutomationAgent"
Description = "Production blueprint for sales automation with least-privilege access"
Owner = @{ "@odata.type" = "microsoft.graph.user"; Id = "your-admin-object-id" }
Sponsor = @{ "@odata.type" = "microsoft.graph.user"; Id = "business-owner-object-id" }
}
$blueprint = New-MgBetaAgentIdentityBlueprint -BodyParameter $blueprintParams
Add a secure client secret (90-day rotation recommended)
$secret = Add-MgBetaClientSecretToAgentIdentityBlueprint -AgentIdentityBlueprintId $blueprint.Id
Write-Host "Client Secret ID: $($secret.KeyId) - Expires: $($secret.EndDateTime)" -ForegroundColor Green
Configure inheritable Graph permissions (least privilege!)
$permissions = @{
PermissionScopes = @(
@{ Id = "e1fe6dd8-ba31-4d61-89e7-88639da4683d"; Type = "Delegated" } Mail.Read
@{ Id = "14dad69e-099b-42c9-8ae5-d1b59a4f97b1"; Type = "Application" } User.Read.All
)
}
Add-MgBetaInheritablePermissionsToAgentIdentityBlueprint -AgentIdentityBlueprintId $blueprint.Id -BodyParameter $permissions
Provision an actual Agent Identity from the blueprint
$agentId = New-MgBetaAgentIdForAgentIdentityBlueprint -AgentIdentityBlueprintId $blueprint.Id
Write-Host "Agent Identity created with ID: $($agentId.Id)" -ForegroundColor Green
What this does: The script creates a blueprint template that defines how agents are created, what permissions they inherit, and who owns them. When you provision an agent identity from this blueprint, the credential container on the blueprint is used to request access tokens — meaning the agent itself never holds credentials directly, eliminating a major attack vector.
- Eliminate Attack Surface by Removing Service Principal Secrets
The most effective mitigation isn’t just migrating agents — it’s eliminating credentials entirely. Microsoft Security recently stated: “Most attackers don’t break in — they log in with stolen credentials.” Credential elimination is no longer an advanced task for mature organizations; it’s a baseline defense against opportunistic attacks. Switching from service principal secrets to managed identities eliminates credential rotation overhead, removes the most common initial access vector for cloud breaches, and costs nothing extra in licensing.
Step‑by‑step migration from service principal to user-assigned managed identity:
Create a user-assigned managed identity
az identity create \
--name secure-app-identity \
--resource-group your-rg \
--location uksouth
Capture the client ID for later use
export UA_CLIENT_ID=$(az identity show \
--name secure-app-identity \
--resource-group your-rg \
--query clientId -o tsv)
export UA_PRINCIPAL_ID=$(az identity show \
--name secure-app-identity \
--resource-group your-rg \
--query principalId -o tsv)
Assign the identity to an App Service (or any Azure resource)
export UA_RESOURCE_ID=$(az identity show \
--name secure-app-identity \
--resource-group your-rg \
--query id -o tsv)
az webapp identity assign \
--name your-app-name \
--resource-group your-rg \
--identities $UA_RESOURCE_ID
Grant least-privilege RBAC at the resource level
az role assignment create \
--assignee $UA_PRINCIPAL_ID \
--role "Key Vault Secrets User" \
--scope /subscriptions/{sub-id}/resourceGroups/your-rg/providers/Microsoft.KeyVault/vaults/your-kv
az role assignment create \
--assignee $UA_PRINCIPAL_ID \
--role "Storage Blob Data Reader" \
--scope /subscriptions/{sub-id}/resourceGroups/your-rg/providers/Microsoft.Storage/storageAccounts/your-storage
What this does: Creates a managed identity that Azure handles automatically — no secrets to rotate, no certificates to expire, no human error in credential storage. The identity becomes tied to the workload itself, not to a config file that can leak. Microsoft updated its official guidance to name user-assigned managed identities the recommended default for Azure workloads precisely because of these security advantages.
Production hardening — avoid DefaultAzureCredential pitfalls:
// BAD: DefaultAzureCredential falls back through multiple authentication methods var credential = new DefaultAzureCredential(); // GOOD: Explicitly use managed identity in production var credential = new ManagedIdentityCredential(clientId);
Using `DefaultAzureCredential` in production introduces risk — if `ManagedIdentityCredential` fails silently, the credential chain falls through to `AzureCliCredential` or other methods, potentially authenticating with an entirely different identity than intended. Microsoft’s SDK documentation explicitly recommends using `ManagedIdentityCredential` directly in production.
What Undercode Say:
- Classic agents are ungoverned backdoors. Every service principal agent without a blueprint association bypasses Conditional Access, Identity Protection, and proper audit trails — creating a massive blind spot that attackers are already learning to exploit.
-
Credential theft is now the primary attack vector. With 35% of cloud security incidents driven by credential theft, eliminating secrets entirely via Managed Identity is no longer optional — it’s table stakes. Microsoft’s shift to workload identities reflects this reality.
-
Agent migration requires active defense, not passive waiting. The “buggy version” audit script isn’t a bug — it’s a gift. Running it today reveals exactly where your tenant is vulnerable. Organizations that wait for Microsoft’s official migration tool will leave their classic agents exposed for months.
-
The Agent ID Administrator vulnerability proved the danger. When Silverfort discovered that the Agent ID Administrator role could hijack arbitrary service principals, it demonstrated exactly how classic agents become escalations paths. Microsoft patched it, but the lesson remains: ungoverned workload identities amplify risk faster than any other cloud asset.
-
Your migration strategy must be offensive, not defensive. Treat every classic agent as already compromised. Audit aggressively, rotate all credentials before migration, and assume breach during the transition window.
Prediction:
By Q1 2027, Microsoft will deprecate classic service principal agents entirely and force automated migration — but the interim gap will see at least two major cloud breaches directly attributed to forgotten classic agents. Security teams that proactively migrate before official tools arrive will avoid the wave of exploitation targeting those who waited. The Agent 365 licensing model ($15/user/month) isn’t just about feature access — it’s a signal that Microsoft is sunsetting unmanaged workload identities entirely. The clock is ticking.
▶️ Related Video (80% Match):
🎯Let’s Practice For Free:
IT/Security Reporter URL:
Reported By: Derkvanderwoude Bbtg – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅


