This detection identifies adversaries establishing new Entra ID role-assignable groups as a stealthy precursor for privilege escalation by leveraging these groups to assign high-level permissions in subsequent steps. SOC teams should proactively hunt for this activity within Azure Sentinel because it represents a rare, tightly-permissioned event that often signals the early stages of an attack chain aimed at expanding access rights before executing lateral movement or data exfiltration.
let timeframe = 14d;
AuditLogs
| where TimeGenerated >= ago(timeframe)
| where Category =~ "GroupManagement"
| where OperationName =~ "Add group"
| where Result =~ "success"
| mv-expand ModProp = TargetResources[0].modifiedProperties
| extend PropName = tostring(ModProp.displayName)
| extend NewValue = tostring(ModProp.newValue)
| where PropName has "IsAssignableToRole" or NewValue has "isAssignableToRole"
| where NewValue has "true"
| extend GroupName = tostring(TargetResources[0].displayName)
| extend GroupId = tostring(TargetResources[0].id)
| extend ActorUpn = tostring(InitiatedBy.user.userPrincipalName)
| extend ActorApp = tostring(InitiatedBy.app.displayName)
| extend Actor = iff(isnotempty(ActorUpn), ActorUpn, ActorApp)
| extend ActorIp = iff(
isnotempty(tostring(InitiatedBy.user.ipAddress)),
tostring(InitiatedBy.user.ipAddress),
tostring(InitiatedBy.app.ipAddress))
| extend AccountName = iff(ActorUpn has "@", tostring(split(ActorUpn, "@")[0]), Actor)
| extend AccountUPNSuffix = iff(ActorUpn has "@", tostring(split(ActorUpn, "@")[1]), "")
| project
TimeGenerated,
GroupName,
GroupId,
Actor,
AccountName,
AccountUPNSuffix,
ActorIp,
CorrelationId
| sort by TimeGenerated desc
id: 745c2179-a7db-4185-90c1-b33d78c5a6ac
name: Role-assignable group created
description: |
Identifies creation of a new Entra ID role-assignable group, a rare and tightly-permissioned event that can be a precursor to privilege escalation via later membership and role assignment changes.
description-detailed: |
Group role-assignability (isAssignableToRole set to true) can only be set
when a group is created; Microsoft Entra ID does not allow converting an
existing group into a role-assignable one afterward, and creating one
requires the actor to hold at least the Privileged Role Administrator role.
By design there is no legitimate high-volume use of this event in a
well-run tenant, and a maximum of 500 role-assignable groups are permitted
per tenant, so every match here is inherently rare and should map to a
known change.
An attacker who has obtained Privileged Role Administrator or Global
Administrator access can create a role-assignable group with an innocuous
display name, then add members or owners to it and later assign a directory
role to the group. Because role-assignable groups exist specifically so that
group membership grants a role, standard "Add member to role" monitoring
never fires for the accounts that gain access this way; the group creation
and its membership changes are the only audit signal. See the companion
hunting query for member and owner additions shortly after creation.
Analysts should confirm the creation aligns with a documented change and
check which accounts currently hold the Privileged Role Administrator role.
References:
- https://learn.microsoft.com/entra/identity/role-based-access-control/groups-concept
- https://attack.mitre.org/techniques/T1098/003/
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
tactics:
- PrivilegeEscalation
- Persistence
relevantTechniques:
- T1098.003
query: |
let timeframe = 14d;
AuditLogs
| where TimeGenerated >= ago(timeframe)
| where Category =~ "GroupManagement"
| where OperationName =~ "Add group"
| where Result =~ "success"
| mv-expand ModProp = TargetResources[0].modifiedProperties
| extend PropName = tostring(ModProp.displayName)
| extend NewValue = tostring(ModProp.newValue)
| where PropName has "IsAssignableToRole" or NewValue has "isAssignableToRole"
| where NewValue has "true"
| extend GroupName = tostring(TargetResources[0].displayName)
| extend GroupId = tostring(TargetResources[0].id)
| extend ActorUpn = tostring(InitiatedBy.user.userPrincipalName)
| extend ActorApp = tostring(InitiatedBy.app.displayName)
| extend Actor = iff(isnotempty(ActorUpn), ActorUpn, ActorApp)
| extend ActorIp = iff(
isnotempty(tostring(InitiatedBy.user.ipAddress)),
tostring(InitiatedBy.user.ipAddress),
tostring(InitiatedBy.app.ipAddress))
| extend AccountName = iff(ActorUpn has "@", tostring(split(ActorUpn, "@")[0]), Actor)
| extend
| Sentinel Table | Notes |
|---|---|
AuditLogs | Ensure this data connector is enabled |
Here are 5 specific false positive scenarios for the “Role-assignable group created” detection rule, including suggested filters or exclusions:
Automated Onboarding Workflow via Power Automate
Initiator (or AppId) matches the specific Application ID of the onboarding Power Automate flow, and the group name contains a standardized prefix like “Auto-Onboard-”.Scheduled Compliance Group Provisioning
Initiator is the “Compliance-Service-Account” and the group description contains “Temporary Audit”.Third-Party Identity Governance Tool (e.g., Saviynt or SailPoint)
AppDisplayName corresponds to the specific identity governance tool (e.g., “S