
An attacker with only Application Administrator rights in your Entra ID tenant can silently add a certificate credential to a Microsoft first-party service principal, authenticate as that privileged application, and escalate to Global Admin — all without touching a single user account. This Entra ID service principal hijacking path has existed since 2019, and despite incremental fixes, residual gaps remain in default tenants today.
For security engineers responsible for Azure and Microsoft 365 environments, understanding the split between app registrations and service principals is no longer optional. This post breaks down the full attack chain — from credential backdooring to federated domain abuse and SAML token forgery — and explains exactly what Microsoft has fixed, what it hasn’t, and how to harden your tenant.
Key Takeaways
- You'll learn how the Entra ID application model's split between app registrations and service principals creates credential backdoor opportunities that are completely invisible in the portal, allowing attackers to impersonate applications without detection.
- You'll be able to identify which Microsoft first-party applications in your tenant still accept credential assignments, and understand the precise conditions under which an App Admin role can escalate to Global Admin via service principal hijacking.
- Apply the app instance property lock setting to your own published applications and proactively audit service principal credentials in your tenant to detect and prevent this Entra ID privilege escalation path.
Entra ID Application Model: App Registrations vs. Service Principals
Understanding identity and access management in Azure begins with understanding why the application model creates the conditions for service principal hijacking. In Entra ID, every application is not one object — it is two.
The Two-Object Model: App Registration and Service Principal
The app registration is the definition of an application: who created it, what it does, and what permissions it requires to function. Think of it as the blueprint.
The service principal is the identity — the live, operational object that actually takes actions on the application’s behalf within a specific tenant. Think of it as the running instance.
When you create an application and deploy it to your own tenant, you have both objects in that tenant: an app registration and a service principal. When another organization installs your application in their tenant, they get a service principal added to their consuming tenant — a local identity for your app within their environment — while your app registration remains in the publishing tenant.
The application ID is the link that ties both objects together across tenants.
Properties: Inherited, Derived, and Independent
Not all properties flow the same way between the two objects. This is where the trust model gets complicated:
- Directly inherited properties: The application ID — the immutable identifier that links the app registration to all service principals across every tenant where the app is installed.
- Derived properties: Permissions are defined on the app registration (what permissions the app needs), but an administrator must explicitly consent to add them to the service principal. For example:
- App role assignments (application permissions): service-account-style permissions the app uses without user interaction.
- OAuth 2.0 delegated permission grants: permissions that allow the app to act on behalf of a signed-in user.
- Independent properties — the critical gap:
keyCredentialsandpasswordCredentialscan be set on either the app registration or the service principal — and they do not synchronize. A credential assigned to the service principal is completely independent from credentials on the app registration.
Why This Creates a Backdoor Surface
This independence is the core architectural fact that enables this attack class. Because credentials are independently assignable on the service principal:
- An app owner who adds a credential to the app registration can authenticate as that application in every tenant where it is installed.
- An attacker who adds a credential to a local service principal in a consuming tenant can impersonate that application within that tenant — without the app owner’s knowledge, and without any credential appearing on the app registration itself.
Two roles and one permission make credential assignment possible:
- Application Administrator role
- Cloud Application Administrator role
- Application.ReadWrite.All permission (if held by a compromised application)
- Any user or application that holds Owner over the target application
The Visibility Gap: What the Portal Hides
The practical stealth advantage of this technique is that credentials added to service principals are not visible in the Entra ID portal the way credentials on app registrations are. An attacker who backdoors a service principal is taking actions as an application — not as a named user — which reduces the likelihood of detection compared to using a compromised user account.
Microsoft’s First-Party Applications as Targets
The Azure portal is not a single web application. It is a mesh of interconnected services backed by Microsoft’s own first-party applications — installed by default in every tenant. These first-party service principals carry significant permissions (including highly privileged Microsoft Graph scopes and Entra ID roles), making them attractive targets. Because the credentials on these service principals are not prominently surfaced in the portal, backdooring one is both technically feasible (subject to role conditions discussed in later sections) and operationally stealthy.
This foundational architecture — two objects, independently credentialed, with a visibility gap on the service principal side — is what makes the full privilege escalation chain described in this research possible.
Actionable Takeaways
- Audit service principal credentials in your tenant using the Microsoft Graph API directly (not just the portal). Query the
keyCredentialsandpasswordCredentialsproperties on service principal objects — especially for Microsoft first-party apps — since the portal does not surface these. Any unexpected credentials on a service principal should be treated as a potential backdoor and investigated immediately. - Treat Application Administrator and Cloud Application Administrator as high-privilege roles in your threat model. Because holders of these roles can add credentials to service principals, compromising an account with either role is functionally equivalent to compromising any application that role can reach — including high-privilege first-party Microsoft applications in your tenant.
- If you publish applications that other tenants consume, enable the app instance property lock setting on your app registration. This prevents administrators in consuming tenants from adding credentials to the local service principal for your app, closing the local privilege escalation path described in this research.
Common Pitfalls
- Assuming the Entra ID portal gives a complete picture of application credentials. The portal surfaces credentials on app registrations clearly, but credentials assigned directly to service principals are much less visible. Relying on portal views alone will miss backdoored service principals — direct Graph API queries are required for a complete audit.
- Treating Application Administrator as a low-risk administrative role. Because this role can assign credentials to service principals — including those of privileged first-party applications — it represents a viable privilege escalation path to Global Admin under the right conditions. The role should be granted sparingly and monitored as a tier-0 equivalent in environments with unprotected first-party service principals.
Service Principal Hijacking: History, Threat Actor Activity, and Attack Mechanics
Credential backdooring via service principals has a documented public history stretching back to 2019 — and understanding that timeline is critical for any security engineer assessing risk in Microsoft 365 or Azure environments. This isn’t a newly discovered edge case; it’s an attack class that has been reported, partially fixed, re-exploited, and partially fixed again across multiple iterations.
2019: The Original Disclosure
In 2019, researcher Dirk-jan Mollema published a blog post demonstrating that Microsoft’s own first-party applications could be abused for privilege escalation and persistence within Entra ID (then Azure AD) tenants. The attack relied on the fact that credentials — secrets and certificates — could be assigned to the local service principal of a first-party Microsoft application, allowing an attacker to impersonate that application within the consuming tenant.
Mollema originally reported the finding to the Microsoft Security Response Center (MSRC). MSRC initially responded that the issue had been fixed. When he verified that it had not been fixed, MSRC revised their position: the behavior was by design, justified by usability reasons related to local credential assignment for debugging purposes. With no fix forthcoming, he published the research publicly.
2020: Threat Actor Attention and the Storm Spotter Tool
By 2020, threat actors had begun paying attention to service principal abuse — not exclusively targeting first-party applications, but using the general application credential assignment mechanism for persistence and lateral movement. This represented the first documented real-world exploitation of the attack class in the wild.
In response, the Azure team released Storm Spotter[1], a tool designed to help defenders map the permissions held by service principals and quantify the risk that highly privileged applications posed to a tenant. The tool was an early attempt to surface visibility into an attack surface that the Entra portal obscured by design.
Also in 2020, researchers Amelia Chtchuk and Christian Philippov presented at fwd:cloudsec, highlighting the scale of the problem: there were over 300 first-party Microsoft applications in a default Entra tenant, each a potential hijacking target for an attacker with the right role assignments.
2022: Active Exploitation and the App Instance Property Lock
By 2022, threat actors were actively exploiting service principal credential backdooring against Microsoft first-party applications — not just generic application abuse. This escalation in real-world activity appears to have influenced Microsoft’s decision to introduce the app instance property lock, a new application registration setting that, when enabled by a developer, prevents credentials from being added to local service principal instances of that application in consuming tenants.
The app instance property lock was a meaningful mitigation — but Microsoft did not retroactively apply it to all of their own first-party applications. Researcher Eric Woodruff’s follow-on work found that while the pool of vulnerable first-party apps had shrunk from the original 300-plus, a residual set of Microsoft applications still permitted credential assignment and privilege escalation to Global Admin, sometimes via undocumented permissions.
Microsoft’s Evolving Position
The MSRC response across this timeline reflects a gradual shift in posture:
- 2019: “This is by design. Feel free to publish.”
- Post-2022 exploitation: “We don’t see this as a material flaw, but we can see why you might — we’ll start to fix it.”
- Post-Woodruff research: Specific apps (SharePoint, Exchange Online) now require Global Admin to assign credentials; most first-party apps no longer accept local credential assignment at all.
Despite this progress, the pattern of incremental fixes and residual gaps motivated Katie Nolles to test whether any exploitable surface remained in a default tenant.
Who Can Execute This Attack
The core attack mechanic requires one of the following in the target (consuming) tenant:
- Application Administrator role
- Cloud Application Administrator role
- Owner of the target application object
- An application or service principal with the Application.ReadWrite.All Microsoft Graph permission
With any of these, an attacker can issue a POST request to the Microsoft Graph API[2] addPassword endpoint on a service principal object, supplying only a display name, and receive back a functional secret credential. That credential can then be used in the client credentials OAuth flow to obtain a JWT token authenticated as the target service principal — inheriting all of its Entra ID roles and Microsoft Graph permission scopes.
For applications that reject secrets and require certificate authentication, the attacker can bypass the addKey endpoint’s proof-of-possession requirement entirely by directly issuing a PATCH request to the service principal object with a base64-encoded certificate, then constructing a self-signed JWT assertion to exchange for a valid Entra token.
Why This Attack Class Persists
Two structural factors keep this attack surface alive:
- Portal invisibility: Credentials assigned directly to a service principal object are not visible in the Entra portal. An App Admin can silently add a backdoor credential to a privileged service principal, and defenders have no obvious place to look for it without direct Graph API queries.
- Taking action as an application, not a user: Malicious activity performed as a service principal identity logs differently than user actions. Defenders expecting to hunt user-account-based escalation may overlook application-identity abuse entirely.
Together, these factors make service principal credential backdooring a high-value persistence and escalation technique that remains viable in any tenant where the app instance property lock is not universally applied.
Actionable Takeaways
- Audit all service principals in your tenant for unexpected credentials using the Microsoft Graph API (
GET /servicePrincipals/{id}/keyCredentialsand/passwordCredentials) — the Entra portal does not surface these. Any credential whosestartDateTimeyou cannot attribute to a known provisioning event should be treated as suspicious. - Verify that the app instance property lock (
isEnabled: trueunderservicePrincipalLockConfiguration) is set on all internally published applications in your tenant. Do not assume it is enabled by default; check explicitly for any application that could be installed into partner or customer tenants. - Treat Application Administrator and Cloud Application Administrator as high-privilege roles with a viable Global Admin escalation path in tenants where residual vulnerable first-party service principals exist. Scope assignment of these roles as tightly as you would Global Admin itself, and monitor for credential additions to service principals via audit log category
ServicePrincipalManagement.
Common Pitfalls
- Assuming that because Microsoft has "fixed" service principal hijacking, the attack surface no longer exists. The fix has been applied incrementally — most first-party apps can no longer accept local credentials, but a small residual set (including Exchange Online and SharePoint in some configurations) still requires Global Admin explicitly to block it, rather than being locked by default.
- Relying on the Entra portal as a complete view of application credentials. The portal does not display key credentials or password credentials assigned directly to service principal objects. Defenders who do not query the Graph API directly will have a blind spot to backdoored service principals.
Credential Backdooring Microsoft First-Party Service Principals via Graph API
The most instructive part of this research was the deliberate choice to use the Microsoft Graph API[2] directly rather than PowerShell or the Azure CLI. While those tools are far more convenient for everyday administration, they abstract away the raw object properties that make service principal hijacking possible. Working at the API level forces you to see exactly what properties exist on each object, what values they accept, and where the trust boundaries actually live.
Phase 1 — Adding a Secret to Every First-Party Service Principal
The attack begins with a simple ambition: attempt to add a password credential (secret) to every Microsoft first-party service principal in a default Entra ID tenant. The Graph API call for this is a POST request to the addPassword endpoint on the service principal object:
POST /v1.0/servicePrincipals/{id}/addPassword
Body: { "passwordCredential": { "displayName": "backdoor" } }
The only required field is a display name. When the request succeeds, the API returns the secret value immediately — the only time it will ever be visible. From that point forward, an attacker holding that secret can authenticate as the service principal using the client credentials flow:
POST https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token
grant_type=client_credentials
&client_id={app_id}
&client_secret={secret}
&scope=https://graph.microsoft.com/.default
The resulting JWT is the key artifact. Decoding it reveals two critical pieces of information:
scp/rolesclaims — The Microsoft Graph permission scopes assigned to this service principal (e.g.,Domain.ReadWrite.All,Directory.ReadWrite.All)widsclaim — The Entra ID directory roles assigned to the service principal identity (e.g., Cloud Application Administrator)
The wids claim is particularly valuable during enumeration because it confirms which Entra ID roles are held by the application identity — often surfacing privileges that are not obvious from the portal view.
Phase 2 — Handling Certificate-Only Applications
Several Microsoft first-party service principals returned an error when a secret was added: the application only accepts certificate credentials, not passwords. This is the first fork in the attack path and requires a different approach.
The expected route for adding a certificate credential to a service principal is the addKey endpoint:
POST /v1.0/servicePrincipals/{id}/addKey
However, this endpoint has a prerequisite: you must prove you already hold a valid credential for that application by signing a proof-of-possession JWT with an existing certificate. An attacker starting from scratch does not have a certificate that Entra already trusts for a Microsoft first-party app. The endpoint is therefore a dead end on first approach.
The workaround, documented in Microsoft’s own API reference, is to directly PATCH the service principal object and write a base64-encoded certificate into the keyCredentials property:
PATCH /v1.0/servicePrincipals/{id}
Body: {
"keyCredentials": [{
"customKeyIdentifier": "<thumbprint-b64>",
"displayName": "backdoor-cert",
"key": "<cert-der-b64>",
"type": "AsymmetricX509Cert",
"usage": "Verify"
}]
}
This bypasses the proof-of-possession requirement entirely. Once the certificate is written to the service principal object, the attacker can authenticate using it.
Phase 3 — Certificate-Based Token Exchange
To authenticate as a service principal using a certificate, the client must construct and sign a client assertion JWT (also called a client credential assertion). This JWT is signed with the private key corresponding to the certificate that was just written into the keyCredentials property. Its structure includes:
- Header:
alg(RS256),x5t(base64url-encoded certificate thumbprint) - Payload claims:
aud(token endpoint URL),iss(client ID / app ID),sub(client ID),jti(unique ID),exp/nbf(expiry window)
This self-signed JWT is then submitted to the token endpoint:
POST https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token
grant_type=client_credentials
&client_id={app_id}
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion={signed_jwt}
&scope=https://graph.microsoft.com/.default
Entra ID validates that the JWT was signed by the private key of a certificate it trusts for that service principal (i.e., one now listed in keyCredentials), and if valid, returns a bearer token for the application identity.
Phase 4 — Confirming Access and Enumerating Roles
After obtaining a token, the research methodology included decoding it to enumerate the scopes and Entra ID roles available to the hijacked service principal. In the specific case demonstrated, the backdoored service principal was the Office 365 Exchange Online application.
The decoded token revealed the Domain.ReadWrite.All Microsoft Graph permission. This permission allows the holder to:
- Add custom domains to an Entra ID tenant
- Verify domain ownership
- Configure federation settings for domains
At this point the attacker is not just authenticated as the application — they appear in audit logs as the Office 365 Exchange Online service principal. Any subsequent actions are attributed to that application identity, not to the attacker’s user account. This is the core stealth advantage of service principal backdooring over direct user account compromise.
Why First-Party App Role Assignments Are Invisible in the Portal
One important operational detail: when you attempt to read appRoleAssignments from a Microsoft first-party service principal via the Graph API, the result comes back empty. These role assignments are not exposed through the standard service principal properties endpoint for Microsoft’s own applications. This is why the JWT token decode — rather than a direct API query for roles — is the correct method for confirming what access a hijacked first-party service principal actually holds.
Scope of Vulnerability in Default Tenants
Testing against approximately 500 Microsoft first-party service principals in a default tenant yielded only five that accepted credential additions. Of those, a subset returned the certificate-only error and required the direct PATCH approach. The attack surface has been substantially reduced over the years through the app instance property lock mechanism — but the residual cases include high-value applications like Office 365 Exchange Online and SharePoint Online that carry Domain.ReadWrite.All and other sensitive permission scopes.
Adding a Secret and Certificate Credential to a Microsoft First-Party Service Principal via Microsoft Graph API
Proof of Concept
-
Enumerate first-party service principals in the tenant. Using an authenticated Microsoft Graph API session, enumerate all service principals present in the default tenant. Microsoft’s first-party applications are installed by default; over 300 were found in a default tenant in prior research, though recent Microsoft mitigations have reduced the count of vulnerable apps significantly.
- Attempt to add a secret (password credential) to each service principal. Issue a POST request to the Graph API’s
addPasswordendpoint for each target service principal:POST https://graph.microsoft.com/v1.0/servicePrincipals/{id}/addPassword Body: { "passwordCredential": { "displayName": "<chosen display name>" } }A successful response returns a plaintext secret value. Store the returned secret and the application’s
appIdfor use in authentication. This is the “local credential backdoor” — the credential is scoped to the local identity (service principal) in the consuming tenant and does not appear in the app registration or synchronize upstream. - Handle certificate-only responses. Several first-party service principals return an error indicating that secrets are not permitted and a certificate credential must be used instead. For these applications, do not use the
addKeyendpoint (which requires proof of existing certificate possession). Instead, issue a PATCH request directly to the service principal object, providing a Base64-encoded public key certificate:PATCH https://graph.microsoft.com/v1.0/servicePrincipals/{id} Body: { "keyCredentials": [ { "type": "AsymmetricX509Cert", "usage": "Verify", "key": "<b64-encoded-cert>" } ] }This bypasses the proof-of-possession requirement imposed by the
addKeyendpoint. - Authenticate as the target service principal using the client credentials flow. For secret-backed service principals, submit a standard OAuth 2.0 client credentials grant to Microsoft’s login endpoint:
POST https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token Body: grant_type=client_credentials client_id=<appId> client_secret=<secret> scope=https://graph.microsoft.com/.defaultFor certificate-backed service principals, construct a self-signed JWT (client assertion) that includes the certificate thumbprint in the
x5theader, signs the token with the private key corresponding to the backdoored certificate, and presents it to the token endpoint as aclient_assertion. - Decode the returned JWT access token. The access token returned by Microsoft’s authentication service is a JWT. Decode it to enumerate:
rolesclaim: Microsoft Graph permission scopes (application permissions) granted to the service principal.widsclaim: Entra ID directory role GUIDs assigned to the service principal’s identity.
-
Identify high-value permission scopes. Review all roles and permissions present in the decoded token. In the demonstrated case, authenticating as the Office 365 Exchange Online service principal revealed the
Domain.ReadWrite.AllMicrosoft Graph permission — a scope that permits adding, verifying, and removing domains in the tenant. - Confirm stealth characteristics. Note that credentials added to service principals are not visible through the Entra portal’s standard UI in the same way as credentials on app registrations. Actions taken using the backdoored service principal token appear in audit logs attributed to the application identity, not to any user account.
Actionable Takeaways
- Audit all service principal objects in your tenant for unexpected
keyCredentialsandpasswordCredentialsentries using the Microsoft Graph API directly (not the portal). The portal does not surface credentials added to service principals the same way it does for app registrations, and hidden backdoor credentials will only be visible at the API level. - When investigating a potentially compromised service principal token, decode the JWT and inspect both the
roles/scpclaims (Graph permissions) and thewidsclaim (Entra ID directory roles). Thewidsclaim often reveals Entra ID role assignments that are not immediately apparent from the portal and can indicate the true privilege level of a hijacked identity. - Deliberately test your own environment's first-party service principals by attempting to POST to the
addPasswordendpoint. If any succeed for applications other than ones you expect to accept credentials, treat the result as a finding and escalate to review whether those applications carry sensitive permission scopes such asDomain.ReadWrite.AllorDirectory.ReadWrite.All.
Common Pitfalls
- Relying on the Entra portal to audit service principal credentials creates a blind spot. Credentials added directly to service principal objects via Graph API are not displayed in the same credential management view used for app registrations. Organizations that conduct credential audits exclusively through the portal will miss backdoor credentials on service principals entirely.
- Assuming that app role assignment enumeration via the standard service principal API endpoint is sufficient to understand first-party app privileges. Microsoft first-party service principal
appRoleAssignmentsreturn empty from the API. The actual permissions only become visible by obtaining and decoding a token for that service principal.
Federated Domain Abuse and SAML Token Forgery for Global Admin Escalation
Once an attacker holds a token as a privileged Microsoft first-party service principal — in this case, the Office 365 Exchange Online application — the attack surface extends well beyond what most defenders expect. The Domain.ReadWrite.All permission, surfaced during JWT decoding after credential backdooring, unlocks a chained escalation path that exploits how Entra ID models federated identity trust: the same mechanism organizations use to bridge on-premises Active Directory with cloud authentication via ADFS.
This attack class was first documented in 2018 by Dr. Nestori Syynimaa (AAD Internals author), who demonstrated adding a federated domain backdoor via the Azure Active Directory Graph API. By 2020, threat actors were actively weaponizing the technique — most notably during the SolarWinds supply chain attack, where forged SAML tokens were used to authenticate as cloud identities without possessing their credentials or triggering MFA bypass.
Step 1: Add an Attacker-Controlled External Domain
Using the token obtained as the Office 365 Exchange Online service principal, the attacker registers an external domain they control into the victim tenant. In the demonstrated case, this was 40th-cop.net — a domain visually similar to the legitimate tenant domain but owned by the attacker.
The process follows the standard domain verification flow:
- Make an authenticated API call (using the service principal token) to add the external domain to the Entra ID tenant
- Request a DNS TXT verification record from Entra ID for that domain
- Add the TXT record to the attacker’s own DNS configuration for the domain
- Call the verification endpoint to confirm domain ownership to Entra ID
The verification step is entirely under the attacker’s control — they own the domain, so DNS propagation is trivial. All of these actions are logged under the service principal’s identity, not a user account. This is a key detection consideration: audit logs will show the Office 365 Exchange Online application performing domain management operations, which may not trigger standard user-focused anomaly detection.
Step 2: Configure a Federation Trust with an Attacker-Controlled Certificate
With the domain verified, the attacker creates a federation configuration for it. In a legitimate ADFS deployment, this federation config tells Entra ID: “Trust SAML tokens signed by this certificate as valid authentication assertions for users in this federated domain.”
The attacker supplies their own certificate — one they generated and control — as the trusted signing certificate for the federation. Entra ID accepts this configuration because it was submitted via an authenticated API call bearing valid service principal credentials with the required permissions.
At this stage, the attacker does not need the domain itself at all anymore. The domain was only a vehicle for establishing the federation trust. What matters is that Entra ID now holds a certificate the attacker controls, designated as a trusted token issuer for synchronized users in the tenant.
Step 3: Enumerate the Target User’s Immutable ID
Every user synchronized from on-premises Active Directory to Entra ID carries an immutableId property — a Base64-encoded representation of their on-premises object GUID. This property is what links an on-premises AD identity to its Entra ID counterpart.
Using the service principal token, the attacker queries the Microsoft Graph API for the target user — in the demonstration, a Global Admin account — and retrieves the immutableId field. This identifier is the linchpin of the SAML token forgery: it is the claim that Entra ID uses to resolve which user is authenticating via the federated trust.
Any user with an on-premises identity synchronized to Entra ID is a viable target. This includes Global Admins, Exchange Admins, or any other high-value account that was originally provisioned from Active Directory.
Step 4: Forge the SAML Token and Bypass MFA
With three components in hand — the attacker’s trusted signing certificate, the target user’s immutableId, and an understanding of what Entra ID expects in a valid SAML assertion — the attacker uses AAD Internals[3] to forge the SAML token.
The forged token includes:
- The target user’s
immutableIdas the subject identifier - An MFA bypass claim: because the federated domain is attacker-controlled, MFA assertions from that domain are trusted by Entra ID without challenge. The token simply declares that MFA was satisfied.
- The federation configuration’s issuer metadata pointing to the attacker’s domain
The forged SAML token is submitted to Microsoft’s login services and exchanged for a valid Entra ID access token. The resulting token is issued as the Global Admin user — granting full administrative access across the tenant.
Step 5: Full SSO Access Across Microsoft 365
Because Microsoft 365 is deeply integrated through SSO, a token issued as Global Admin provides seamless access to:
- Azure Portal — full subscription and resource management
- Microsoft 365 Admin Center — user, license, and policy management
- Exchange Online, SharePoint, Teams — all M365 workloads
The attacker navigates these surfaces as the targeted Global Admin, with no further credential theft, password spray, or phishing required.
Why Synchronized Users Are the Specific Target
This attack exclusively targets users whose identities are synchronized from on-premises AD to Entra ID. Cloud-only accounts do not have an immutableId and cannot be targeted via this federated domain mechanism. Organizations that are cloud-native (no on-premises AD, no hybrid sync) are not vulnerable to this specific escalation path.
Hybrid environments — where on-premises AD objects are synced to Entra ID via Azure AD Connect — remain exposed as long as the service principal credential backdoor precondition can be satisfied and the Domain.ReadWrite.All permission is accessible to the compromised service principal.
Attack Chain Summary
The complete Entra ID privilege escalation chain demonstrated in this research:
- Identify a Microsoft first-party service principal that accepts credential assignment (e.g., Office 365 Exchange Online)
- Backdoor the service principal with an attacker-controlled certificate via direct PATCH to the service principal object
- Authenticate as the service principal using the client credentials flow, obtaining a JWT with
Domain.ReadWrite.All - Add an attacker-owned external domain to the victim tenant via the authenticated service principal token
- Verify the domain via DNS (trivial for the attacker who owns it)
- Install a federation configuration with an attacker-controlled signing certificate
- Fetch the immutableId of a synchronized Global Admin via Graph API
- Forge a SAML token using AAD Internals, including an MFA bypass claim
- Exchange the SAML token for an Entra ID access token — authenticated as Global Admin
- Access Azure Portal, M365 Admin Center, and all SSO-integrated services
Federated Domain Backdoor and SAML Token Forgery to Escalate to Global Admin as Any Synchronized User
Proof of Concept
-
Obtain a valid token as the backdoored service principal. Starting from the service principal credential backdoor established in the previous phase, authenticate as the Office 365 Exchange Online service principal using the attacker-controlled certificate and the client credentials flow against Microsoft’s login services. Decode the resulting JWT to confirm possession of the
Domain.ReadWrite.Allpermission scope — this is the prerequisite for the federated domain attack. -
Register an attacker-controlled external domain. Using the token obtained in step 1, issue a POST request to the Microsoft Graph API domains endpoint to add an attacker-owned external domain (e.g.,
40th-cop.net, chosen to superficially resemble the target tenant name) to the Entra ID tenant. This action is logged under the service principal’s identity, not a user account. -
Retrieve and satisfy the DNS verification record. Request the DNS TXT verification record that Entra ID requires to confirm domain ownership. Add this TXT record to the attacker-controlled domain’s DNS configuration. Because the attacker owns the domain, this step is trivially satisfied. Issue the domain verification request to Entra ID to confirm the domain has been added and is under attacker control.
-
Create a federation configuration with an attacker-controlled certificate. Using the verified domain and the service principal token, create a federation configuration on the newly added domain. This configuration designates an attacker-controlled certificate as trusted to issue SAML tokens on behalf of the tenant for any synchronized users. Once the federation configuration is established, the external domain itself is no longer needed — only the trusted certificate matters going forward.
-
Enumerate the immutable ID of the target user. Using the service principal token (which carries sufficient Microsoft Graph API access), query the Entra ID users endpoint for the target account — in this case, a Global Admin. Retrieve the
onPremisesImmutableIdproperty, which is the Base64-encoded GUID of the user’s on-premises Active Directory identity. -
Forge a SAML token using AAD Internals. With the
onPremisesImmutableIdof the target Global Admin and the attacker-controlled certificate (now trusted by the tenant’s federation configuration), use the AAD Internals PowerShell toolkit to forge a SAML assertion. Configure the token to include MFA claims — Entra ID trusts MFA assertions from federated domains, so this entirely bypasses multi-factor authentication requirements. -
Exchange the forged SAML token for an Entra ID access token. Submit the forged SAML token to Microsoft’s login services. Entra ID, trusting the federated domain’s certificate, validates the assertion and issues a legitimate access token scoped to the target Global Admin’s identity.
-
Access M365 and Azure portal as Global Admin. Use the issued token to navigate the Microsoft 365 portal, Azure portal, and any other Microsoft web services integrated via single sign-on.
Actionable Takeaways
- Audit your Entra ID tenant for unexpected federated domain configurations: run a query against the domains endpoint and flag any federation configurations referencing certificates not provisioned by your official ADFS or identity provider deployment. Federated domains added outside of a sanctioned change process are a high-confidence indicator of compromise.
- Alert on service principal activity involving domain management operations. The
Domain.ReadWrite.Allpermission is rarely exercised by application identities in normal operations. Create a conditional alert in your SIEM or Entra ID audit log pipeline for any domain add, verify, or federation configuration event where the actor is a service principal rather than a human admin. - Assess your hybrid identity posture: if your organization does not require on-premises AD synchronization, evaluate a migration to cloud-only identities for privileged accounts. Global Admin and other highly privileged roles operated as cloud-only accounts cannot be targeted by immutableId-based SAML token forgery, significantly reducing the blast radius of a compromised service principal with Domain.ReadWrite.All.
Common Pitfalls
- Assuming MFA protects synchronized privileged accounts against service principal-level compromise. In this attack chain, MFA is entirely bypassed because the forged SAML token includes an MFA satisfaction claim, and Entra ID trusts MFA assertions from the federated domain the attacker controls. Conditional Access policies and MFA requirements do not block a valid, signed SAML assertion from a trusted federation.
- Overlooking service principal audit logs when investigating domain management events. Because all actions in this chain are performed as an application identity (the Office 365 Exchange Online service principal), standard user-focused anomaly detection will not surface the federated domain addition or federation configuration change. Defenders must explicitly monitor service principal activity in domain management audit categories, not just user-driven events.
Research Findings, MSRC Response, and Defensive Hardening for Entra ID Tenants
The Unexpected Edge Case: Service Principal vs. User with App Admin
After chaining credential backdooring into a full Global Admin privilege escalation via federated domain abuse and SAML token forgery, Katie Nolles brought the finding to Microsoft Security Response Center (MSRC). What came back was an unexpected complication that refined the understanding of the vulnerability’s true scope.
MSRC pointed out that all of the research had been conducted while authenticated as a service principal holding the App Admin role — not as a human user with the same role. When Nolles tested the credential assignment against the Office 365 Exchange Online service principal as a user with Application Administrator, the attack failed. It only succeeded under two conditions:
- A user with Global Admin (not App Admin) could assign credentials to the Office 365 Exchange Online service principal
- A service principal with App Admin could also assign credentials — a behavioral inconsistency with no documented explanation
This distinction matters enormously for risk assessment. In standard Entra ID deployments, roles like Application Administrator are commonly assigned to human user accounts. The scenario where a service principal holds App Admin — which is a less common configuration — is what unlocked the escalation path in this research. MSRC’s response acknowledged the finding but classified it as an edge case: because the vulnerable condition required a service principal to hold the App Admin role (rather than a user), they declined to treat it as a material flaw requiring an immediate fix.
What Microsoft Has Fixed — and What Remains
The history of Entra ID service principal hijacking remediation is incremental rather than comprehensive. Understanding the current state of fixes is essential for defenders assessing residual risk in their tenants.
What has been fixed or restricted:
- The vast majority of Microsoft first-party applications in a default tenant — tested across approximately 500 apps — now reject credential assignments entirely. The attack surface has shrunk dramatically from the 300+ vulnerable apps identified in earlier research.
- For the remaining handful of first-party apps (notably SharePoint and Exchange Online service principals), Microsoft has restricted credential assignment so that only Global Admin can add credentials. This raises the bar from App Admin to Global Admin, but does not eliminate the vector entirely.
- The app instance property lock setting was introduced to allow application developers to prevent credential assignment to the local service principal (the consuming tenant’s identity). When enabled, this blocks the local escalation scenario.
What remains unfixed or by-design:
- Microsoft’s documentation still describes the ability to add credentials to service principals as by design, framing it as a usability feature for developers needing to debug or test application identities locally.
- The edge case where a service principal holding App Admin can assign credentials to the Office 365 Exchange Online service principal — which a human user with the same role cannot — was acknowledged but not prioritized for remediation by MSRC.
- The credential invisibility problem persists: credentials added to service principals are not visible through the Entra portal the way app registration credentials are. This makes detection difficult without dedicated tooling or log analysis.
The Evolving Microsoft Posture on Privilege Escalation by Design
The conversation around whether App Admin should be able to escalate to Global Admin has shifted over time, but remains unresolved. Microsoft’s public documentation continues to acknowledge this escalation path as expected behavior. However, the incremental changes — the app instance property lock, restricting Exchange and SharePoint credential assignment to Global Admin only — suggest an unstated direction toward eventually closing these paths entirely.
For defenders, the practical implication is that the risk surface is real but narrowing. The attack chains demonstrated in this research (credential backdooring → federated domain abuse → SAML token forgery → Global Admin) required a specific combination of conditions that are not universally present in every tenant. But those conditions — Microsoft first-party apps that still accept credentials, synchronized users with on-premises immutable IDs, federated domain trust configurations — are common in enterprise environments.
Defensive Hardening: What Defenders Can Apply Today
1. Enable the app instance property lock on your own published applications
If your organization publishes applications that other tenants consume, enabling the appInstanceLock property on your app registration prevents consuming tenants from adding credentials to the local service principal. This directly blocks the local privilege escalation scenario. As of recent Microsoft updates, this setting may be enabled by default for new applications — but verify explicitly for any existing registrations.
2. Audit service principal credentials across your tenant
Because the Entra portal does not surface service principal credentials the same way it surfaces app registration credentials, proactive auditing requires direct API or PowerShell queries. Use the Microsoft Graph API to enumerate keyCredentials and passwordCredentials on service principals — particularly Microsoft first-party service principals — and alert on any unexpected additions.
3. Restrict and monitor App Admin and Cloud App Admin role assignments
The App Admin and Cloud App Admin roles are the primary entry points for this attack class when held by a human user, and the research demonstrates they are also relevant when held by a service principal. Treat assignments of these roles — especially to service principals or non-human identities — as high-risk events requiring review. Prefer scoped application ownership over broad role assignments where possible.
4. Understand your hybrid identity exposure
The federated domain abuse and SAML token forgery chain is only viable against synchronized users — accounts with an on-premises identity linked to Entra ID via the immutable ID property. Cloud-only users are not susceptible to this specific SAML forgery path. Auditing which users are synchronized and ensuring federation configurations are legitimate and minimal reduces the blast radius if a service principal is compromised.
5. Treat service principal role assignments as high-value targets
The research revealed that behavioral differences exist between users and service principals holding the same Entra ID role — in this case, a service principal with App Admin could do something a user with App Admin could not. This asymmetry is not well-documented and suggests that service principals holding privileged roles deserve elevated scrutiny in threat models and access reviews.
Research Philosophy: Think in Conditions, Not Just Outcomes
Beyond the technical findings, Nolles offered a methodological insight that applies broadly to security research: think in precise conditions, not just outcomes. The question is not simply “can App Admin escalate to Global Admin?” but “under exactly what conditions is this escalation possible, and does the answer change depending on whether the principal is a user or a service principal?”
Framing research this way — hyperspecifically about preconditions — is what surfaces the kind of edge cases that MSRC initially misses and that defenders need to understand. It also keeps research grounded when stakeholders push back: if the risk falls naturally out of a precise conditional statement, the argument becomes much harder to dismiss.
Actionable Takeaways
- Enable the app instance property lock on any application your organization publishes. Verify the setting is active on existing registrations — not just new ones — since it may not have been applied retroactively. This single control blocks the local service principal credential assignment vector for any tenant consuming your app.
- Audit service principal
keyCredentialsandpasswordCredentialsdirectly via the Microsoft Graph API or PowerShell on a recurring basis, particularly targeting Microsoft first-party service principals. The Entra portal does not surface these credentials, making API-level enumeration the only reliable detection method. - Treat Entra ID role assignments (App Admin, Cloud App Admin) granted to service principals — rather than human users — as elevated-risk configurations requiring additional scrutiny. The research demonstrates behavioral asymmetries between user and service principal role holders that are undocumented and can unlock otherwise-blocked escalation paths.
Common Pitfalls
- Assuming that App Admin and Cloud App Admin role assignments carry the same risk profile whether held by a human user or a service principal. The research shows a service principal holding App Admin could assign credentials to the Office 365 Exchange Online service principal while a human user with the same role could not — an undocumented behavioral difference that significantly affects threat modeling.
- Relying on the Entra portal as a complete view of service principal credentials. Credentials added to service principals are not displayed in the portal the same way app registration credentials are, creating a blind spot that attackers exploit for persistence. Any defensive posture that does not include direct API-level credential auditing is incomplete.
Conclusion
The research by Katie Nolles at fwd:cloudsec North America 2025 demonstrates that Entra ID security requires understanding the application model at a deeper level than the portal exposes. The split between app registrations and service principals — with independently assignable, non-synchronizing credentials — is the architectural foundation of this entire attack class. Despite six years of incremental remediation, the attack surface persists in any tenant with Microsoft first-party service principals that still accept credential assignments and hybrid identity configurations that expose synchronized user immutableIds.
The full chain — credential backdooring via Graph API → Domain.ReadWrite.All token → federated domain registration → trusted certificate installation → SAML token forgery → Global Admin — bypasses MFA entirely and leaves audit trails attributed to application identities rather than attacker accounts. Defenders who rely solely on user-focused anomaly detection and portal-based credential views will miss this class of attack.
For security engineers building out their cloud security program: audit service principal credentials via Graph API now, enable the app instance property lock on every application you publish, and treat App Admin role assignments to service principals as tier-0 equivalent risks. The attack surface is narrowing — but it is not closed.
Related topics worth exploring on this site:
- Azure Active Directory attack research
- Privilege escalation techniques in cloud environments
- Identity and access management security
References & Tools
- Storm Spotter — Microsoft Azure team tool for mapping permissions held by service principals and quantifying risk of first-party application takeover. ↩
- Microsoft Graph API — The primary REST API interface for Microsoft 365 and Entra ID, used throughout this research for enumerating service principals, adding credentials, and obtaining JWT tokens via the client credentials flow. ↩
- AAD Internals — PowerShell toolkit by Dr. Nestori Syynimaa for Entra ID and Azure AD administration and research, used in the final attack stage to forge SAML tokens with a trusted federated certificate targeting synchronized users' immutable IDs. ↩
Questions from the audience
Related deep dives
The AI Security Larsen Effect - How to Stop the Feedback Loop | [un]prompted 2026
This Wasnt in the Job Description- Building a production-ready AWS environment from scratch
Shared-GPU Security Learnings from Fly.io