Query Details

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:

  1. 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.

  2. 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.
  3. Data Source: The query examines the AuditLogs for successful operations where an app role is assigned to a Service Principal.

  4. 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.
  5. 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.

  6. 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.

  7. 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 profile picture

Fabian Bader

Released: February 5, 2026

Tables

AuditLogs

Keywords

ServicePrincipalMicrosoftGraphApplicationPermissionsAuditLogsUserAgentIPAddress

Operators

letdynamicwhere===~mv-expandisnullextendtrimtostringisnotemptyiffparse_json

Severity

High

Tactics

Persistence

Frequency: 31m

Period: 31m

Actions

GitHub