↳ GitHub sourceAnalytics ruleHigh

Microsoft Entra ID Role Management Permission Grant

Description

'Identifies when the Microsoft Graph RoleManagement.ReadWrite.Directory (Delegated or Application) permission is granted to a service principal. This permission allows an application to read and manage the role-based access control (RBAC) settings for your company's directory. An adversary could use this permission to add an Microsoft Entra ID object to an Admin directory role and escalate privileges. Ref : https://docs.microsoft.com/graph/permissions-reference#role-management-permissions Ref : https://docs.microsoft.com/graph/api/directoryrole-post-members?view=graph-rest-1.0&tabs=http'
Rule type
Scheduled
Version
1.1.1
Declared status
Available
Query frequency
2h
Query period
2h
Trigger
gt 0

Declared MITRE coverage

Declared sources

Metadata from the source file. No dependencies inferred from KQL.

Connectors

Data types

KQL query

Original query, unchanged.

AuditLogs
| where Category =~ "ApplicationManagement" and LoggedByService =~ "Core Directory" and OperationName in~ ("Add delegated permission grant", "Add app role assignment to service principal")
| mv-apply TargetResource = TargetResources on
  (
      where TargetResource.type =~ "ServicePrincipal" and array_length(TargetResource.modifiedProperties) > 0 and isnotnull(TargetResource.displayName)
      | extend props = TargetResource.modifiedProperties
  )
| mv-apply Property = props on
  (
      where Property.displayName in~ ("AppRole.Value","DelegatedPermissionGrant.Scope")
      | extend DisplayName = tostring(Property.displayName), PermissionGrant = trim('"',tostring(Property.newValue))
  )
| where PermissionGrant has "RoleManagement.ReadWrite.Directory"
| mv-apply Property = props on
  (
      where Property.displayName =~ "ServicePrincipal.DisplayName"
      | extend TargetAppDisplayName = trim('"',tostring(Property.newValue))
  )
| mv-apply Property = props on
  (
      where Property.displayName =~ "ServicePrincipal.ObjectID"
      | extend TargetAppServicePrincipalId = trim('"',tostring(Property.newValue))
  )
| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIpAddress = tostring(iff(isnotempty(InitiatedBy.user.ipAddress), InitiatedBy.user.ipAddress, InitiatedBy.app.ipAddress))
| project TimeGenerated, OperationName, Result, PermissionGrant, TargetAppDisplayName, TargetAppServicePrincipalId, InitiatingAppName, InitiatingAppServicePrincipalId,
InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingIpAddress, TargetResources, AdditionalDetails, CorrelationId
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])

Declared entities

AccountIP

Related content

Links established from declared identifiers and solution manifests.

Source provenance

GitHub

Displayed values come from files in Azure/Azure-Sentinel. They describe the published template, not your workspace configuration.

Source identifier
1ff56009-db01-4615-8211-d4fda21da02d
Additional source files 3Solutions/Microsoft Entra ID/Analytic Rules/AzureADRoleManagementPermissionGrant.yamlsource ↗Detections/AuditLogs/AzureADRoleManagementPermissionGrant.yamlmigration-note ↗Solutions/Microsoft Entra ID/Data/Solution_AAD.jsonsolution-membership ↗
GSTEP / CATALOG TRACKING

Added to catalog : 16 Sept 2026 · 05:49 UTC
Last change observed : 16 Sept 2026 · 05:49 UTC

GSTEP sync dates, separate from the source content’s publication dates.