Granting Of High Risk Privilege Escalation Permissions To Service Principal
Query
let DangerousAPIPermissions = dynamic({
"9e3f62cf-ca93-4989-b6ce-bf83c28f9fe8": "RoleManagement.ReadWrite.Directory -> Directly promote any user to global admin",
"06b708a9-e830-4db3-a914-8e69da51d44f": "AppRoleAssignment.ReadWrite.All -> Grant RoleManagement.ReadWrite.Directory, then promote to global admin",
"1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9": "Application.ReadWrite.All -> Act as another entity e.g. a global admin user"
});
AuditLogs
| where OperationName == "Add app role assignment to service principal"
| where Result =~ "success"
| mv-expand TargetResources
| where TargetResources.displayName == "Microsoft Graph"
| mv-expand TargetResources.modifiedProperties
| where TargetResources_modifiedProperties.displayName == "AppRole.Id"
// This permission was not part of this application before
| where isnull(TargetResources_modifiedProperties.oldValue)
// The new permission is part of the dangerous API permissions
| extend NewAPIPermission = trim('"', tostring(TargetResources_modifiedProperties.newValue))
| extend PotentialImpact = DangerousAPIPermissions[NewAPIPermission]
| where isnotempty(PotentialImpact)
| extend UserAgent = iff(AdditionalDetails[0].key == "User-Agent", tostring(AdditionalDetails[0].value), "")
| extend ServicePrincipalDisplayName = parse_json(tostring(parse_json(tostring(TargetResources.modifiedProperties))[6].newValue))
| extend ServicePrincipalObjectID = parse_json(tostring(parse_json(tostring(TargetResources.modifiedProperties))[5].newValue))
| extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))
| extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))Explanation
This query is designed to detect when a Service Principal in Microsoft Entra ID (formerly Azure AD) is granted high-risk permissions that could lead to privilege escalation across the tenant. Here's a simplified breakdown of what the query does:
-
Purpose: It identifies when specific, sensitive permissions are added to a Service Principal, which could allow an attacker to gain extensive control over the tenant if they compromise an account with admin consent capabilities.
-
Monitored Permissions: The query looks for the addition of three specific permissions:
- RoleManagement.ReadWrite.Directory: Allows the app to assign any role, including Global Administrator.
- AppRoleAssignment.ReadWrite.All: Enables the app to grant additional permissions, potentially leading to the above permission.
- Application.ReadWrite.All: Allows the app to modify other applications, possibly adding credentials to act as a highly privileged identity.
-
Data Source: The query examines the AuditLogs for successful operations where an app role is assigned to a Service Principal.
-
Detection Logic:
- It checks if the operation was successful and if the permission was not previously assigned.
- It identifies if the new permission is one of the high-risk permissions listed.
- It captures details such as the user or app that initiated the change, the IP address, and the Service Principal involved.
-
Severity and Frequency: The rule is marked with high severity and runs every 31 minutes. An alert is triggered if any such permission assignment is detected.
-
Alerting: When a high-risk permission is granted, an alert is generated with details about the potential impact. It suggests verifying the necessity of the permission and considering adding the application to a watchlist if needed.
-
Incident Management: The rule creates incidents for each detection without grouping multiple events into a single alert.
Overall, this query helps security teams monitor and respond to potential privilege escalation risks by keeping track of sensitive permission assignments to Service Principals.
Details

Fabian Bader
Released: February 5, 2026
Tables
Keywords
Operators
Severity
HighTactics
Frequency: 31m
Period: 31m