Modern identity systems live or die by their privilege boundaries. In Microsoft Entra ID (formerly Azure AD), one of the most sensitive questions security teams ask is:
Can an application with
Directory.ReadWrite.Allescalate privileges by manipulating group membership?
I ran a series of controlled experiments in my own tenant (where I’m Global Administrator) to answer this precisely—not theoretically, but empirically.
This blog walks through:
- The exact scenarios I tested
- The Graph behavior I observed
- The subtle but critical role of
isAssignableToRole - What this means for Azure RBAC and Entra roles
- The security patterns you should adopt
🔧 Experiment Setup
All tests were performed in a personal Entra ID tenant:
- Tenant:
aspnet4you2.onmicrosoft.com - Admin: I am Global Administrator in this tenant
- Goal: Validate whether an app with
Directory.ReadWrite.Allcan add users to groups that could grant elevated access
Test Application
- Name:
Entra-Permission-Escalation-Demo - Type: App registration in Entra ID
- Permission:
Directory.ReadWrite.All(Application) - Auth: Client credentials (client ID + secret)
- Usage: Called via Postman to invoke Microsoft Graph
Test User
- User:
Paul.Smith@aspnet4you2.onmicrosoft.com - Purpose: Target account to test whether membership changes result in elevated access
Test Groups
I created multiple security groups with different configurations:
- SG-Experiment-Permission-CL
- Microsoft Entra roles can be assigned to the group: Yes
isAssignableToRole = true
- SG-Experiment-Permission-CL4
- Microsoft Entra roles can be assigned to the group: No
isAssignableToRole = false
- SG-Experiment-Permission-CL5
- Microsoft Entra roles can be assigned to the group: No
isAssignableToRole = false- Used specifically to test behavior with Security Reader role
🧪 Scenario 1: Adding a Member to a Role‑Assignable Group
Group: SG-Experiment-Permission-CL
Configuration:
- “Microsoft Entra roles can be assigned to the group” = Yes
- No Entra ID role assigned yet
isAssignableToRole = true
Action:
Using Postman and the app Entra-Permission-Escalation-Demo (with Directory.ReadWrite.All), I attempted to add Paul.Smith as a member:
- HTTP Method:
POST - URL:
https://graph.microsoft.com/v1.0/groups/<group-id>/members/$ref - Body:
{ "@odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/<paul-smith-object-id>" }
Result:
{
"error": {
"code": "Authorization_RequestDenied",
"message": "Insufficient privileges to complete the operation."
}
}
Why This Happens
The moment you set:
Microsoft Entra roles can be assigned to the group = Yes
Entra ID marks the group as:
isAssignableToRole = true
This makes it a role‑assignable group, even if:
- No Entra ID roles are currently assigned
- The group is empty
- You never actually use it for roles
Role‑assignable groups are protected objects. Only:
- Global Administrator
- Privileged Role Administrator
- Certain apps with role management permissions
…can modify them.
Directory.ReadWrite.All is not enough.
✅ Conclusion:
An app with Directory.ReadWrite.All cannot add members to a role‑assignable group.
The security boundary works as intended.
🧪 Scenario 2: Adding a Member to a Normal Group
Group: SG-Experiment-Permission-CL4
Configuration:
- “Microsoft Entra roles can be assigned to the group” = No
isAssignableToRole = false- No roles assigned
Action:
Using the same app and Graph call, I attempted to add Paul.Smith as a member.
Result:
✅ The request succeeded.
Paul.Smith was successfully added to SG-Experiment-Permission-CL4.
Why This Happens
This is a normal security group:
- Not role‑assignable
- Not protected by privileged role boundaries
- Fully modifiable by an app with
Directory.ReadWrite.All
✅ Conclusion:
Normal groups can be modified by apps with Directory.ReadWrite.All.
This is expected behavior.
🧪 Scenario 3: What If These Groups Are Used for Azure RBAC?
I don’t have an Azure subscription attached to this tenant, so I couldn’t test this directly—but the behavior is well‑defined.
Key Point
Azure RBAC roles (Contributor, Owner, Reader, etc.) do NOT make a group role‑assignable.
Assigning a group to an Azure subscription, resource group, or resource does not change isAssignableToRole.
So:
SG-Experiment-Permission-CLisAssignableToRole = true- Protected, regardless of Azure RBAC assignments
- App cannot add members
SG-Experiment-Permission-CL4isAssignableToRole = false- Not protected, even if used for Azure RBAC
- App can add members → users gain Azure RBAC access
✅ Conclusion:
- Azure RBAC does not trigger Entra ID’s privileged group protections
- Only the role‑assignable flag and Entra ID roles matter for this boundary
🧪 Scenario 4: Assigning a Group to a Non‑Privileged Entra ID Role (Security Reader)
Initially, I assumed:
“Non‑privileged roles like Security Reader might allow any group to be assigned without requiring it to be role‑assignable.”
This turned out to be incorrect—and the experiment proved it.
Group: SG-Experiment-Permission-CL5
Configuration:
- “Microsoft Entra roles can be assigned to the group” = No
isAssignableToRole = false
Action:
I attempted to assign SG-Experiment-Permission-CL5 to the Security Reader Entra ID role.
Result:
❌ The group did not even appear in the picker for role assignment.
What This Means
To assign any Entra ID role (privileged or not) to a group, the group must be:
Role‑assignable (
isAssignableToRole = true)
In other words:
- If you want to assign a group to Security Reader, you must first set:
“Microsoft Entra roles can be assigned to the group = Yes” - The moment you do that, the group becomes role‑assignable and is protected
- At that point,
Directory.ReadWrite.Allcannot modify it
So the corrected behavior is:
- You cannot assign a non‑role‑assignable group to Security Reader
- Any group used for Entra ID roles (privileged or not) must be role‑assignable
- And once role‑assignable, it is protected from
Directory.ReadWrite.All
✅ Conclusion:
My earlier assumption that “non‑privileged roles behave differently” was wrong.
All Entra ID role assignments to groups require role‑assignable groups—and those are protected.
🧠 What This Experiment Proves
Across all scenarios, the model is now clear:
1. Role‑Assignable Groups (isAssignableToRole = true)
- Created by:
- Setting “Microsoft Entra roles can be assigned to the group = Yes”
- Behavior:
- Protected from modification by
Directory.ReadWrite.All - Cannot be modified by normal apps
- Required for any Entra ID role assignment (privileged or non‑privileged)
- Protected from modification by
2. Normal Groups (isAssignableToRole = false)
- Cannot be assigned to Entra ID roles at all
- Can be used for:
- Azure RBAC (subscriptions, resource groups, resources)
- Application access
- General security grouping
- Behavior:
- Fully modifiable by apps with
Directory.ReadWrite.All - If used for Azure RBAC, app‑driven membership changes can grant resource access
- Fully modifiable by apps with
3. Azure RBAC vs Entra ID Roles
- Azure RBAC roles (Contributor, Owner, Reader, etc.):
- Do not change
isAssignableToRole - Do not trigger privileged group protections
- Do not change
- Entra ID roles (Global Admin, Security Reader, etc.):
- Require role‑assignable groups
- Those groups are protected from
Directory.ReadWrite.All
🔐 Security Implications
From a security perspective, this experiment leads to several important conclusions:
✅ 1. Tenant Takeover via Entra Roles Is Blocked
An app with Directory.ReadWrite.All:
- Cannot create a role‑assignable group
- Cannot add itself or others to a role‑assignable group
- Cannot use groups to gain Entra ID roles (Global Admin, Security Reader, etc.)
The boundary around isAssignableToRole = true is solid.
⚠️ 2. Azure RBAC via Groups Is Still Sensitive
If you use normal groups for Azure RBAC:
- An app with
Directory.ReadWrite.Allcan add users to those groups - Those users will gain Contributor/Owner/Reader access
- This is not a directory takeover, but it is a resource access escalation
You must treat Azure RBAC groups as high‑impact, even if they’re not role‑assignable.
🛡️ Recommended Security Patterns
Based on these findings, here are practical patterns you can adopt:
1. Use Role‑Assignable Groups Only for Entra ID Roles
- Turn on “Microsoft Entra roles can be assigned to the group” only when needed
- Accept that these groups are protected and cannot be managed by automation with
Directory.ReadWrite.All
2. Treat Azure RBAC Groups as Sensitive
- If you use groups for Azure RBAC:
- Limit which apps have
Directory.ReadWrite.All - Prefer PIM for Azure RBAC
- Monitor group membership changes
- Limit which apps have
3. Minimize Use of Directory.ReadWrite.All
- Avoid granting it broadly
- Use narrowly scoped app permissions where possible
- Regularly review app permissions and secrets
4. Monitor and Audit
- Track:
- Group membership changes
- App sign‑ins
- Permission grants
- Use logs and alerts to detect unusual group modifications
📌 Final Takeaway
This experiment started with a simple but critical question:
Can an app with
Directory.ReadWrite.Alltake over a tenant by adding users to privileged groups?
The answer, after real testing, is:
- No—not for Entra ID roles, because role‑assignable groups are protected
- Yes, potentially—for Azure RBAC, if you rely on normal groups for access and don’t control who can modify them
The real security boundary is:
isAssignableToRoleand the “Microsoft Entra roles can be assigned to the group” toggle—not the role assignment itself.
Understanding that line is essential for designing a secure identity and access model in Entra ID.
If you’re building or reviewing your organization’s Entra ID security posture, this kind of hands‑on validation is invaluable—and I’d strongly recommend replicating similar experiments in a safe lab tenant of your own.
