Entra ID Permission Visibility: Graph API Permissions, OAuth Grants, Conditional Access and PIM
See the cloud attack paths in your Entra ID tenant: abusable Microsoft Graph API permissions, OAuth 2.0 delegated grants, Conditional Access coverage, Privileged Identity Management (PIM) eligible roles, and guest users.
On this page
- Overview
- Prerequisites
- What Gets Detected
- Abusable Microsoft Graph Application Permissions
- OAuth 2.0 Delegated Permission Grants
- Conditional Access Policy Coverage
- PIM Eligible Role Assignments
- Guest User Flagging
- Setting Up Conditional Access and PIM
- Step 1: Add the Required Permission
- Step 2: Trigger a Sync
- Viewing This Data in the Graph
- HasPermission Edges (Abusable App Permissions and Delegated Grants)
- EligibleForRole Edges (PIM)
- AppliedPolicy Edges (Conditional Access)
- Guest Users
- How These Edges Affect Analysis
- Over-Permission Analytics
- Critical Junctions Analysis
- Risk Posture Dashboard
- Troubleshooting
- No abusable app permission edges appear after a sync
- Delegated grant edges don't appear
- Conditional Access edges are missing after you added Policy.Read.All
- PIM edges are missing
- A guest user doesn't show Is guest
- You see many more permission findings
Overview
GraphnAI collects group memberships, role assignments, ownership and app role assignments from Entra ID. It also collects four data sets that expose cloud privilege escalation paths:
- Abusable Microsoft Graph API application permissions. A service principal that holds a permission such as
Application.ReadWrite.Allcan make itself a Global Administrator. Every sync finds these and records them asHasPermissionedges. - OAuth 2.0 delegated permission grants. When a user or an administrator consents to an app acting on their behalf, Entra ID stores a delegated grant. A broad grant, such as
Mail.ReadWriteorDirectory.ReadWrite.All, is a serious risk if the app is compromised. Attackers also abuse them in illicit consent grant attacks. - Conditional Access policy coverage. Shows which users and groups your Conditional Access policies name, so gaps in sign-in policy show up in the graph.
- PIM eligible role assignments. A user eligible for a privileged role can activate it on demand. GraphnAI records that latent privilege as its own edge type,
EligibleForRole, so attack path analysis includes it.
GraphnAI also flags guest users, and links each app registration to the service principal it runs as. See Entra ID Directory Accuracy.
The first data set needs no extra setup. The other three need an optional Microsoft Graph permission or an Entra ID license. The Data collected from this tenant card on Admin > Identity Providers shows which of them your tenant collects. It also says what each one needs and how to fix a gap. See Entra ID Directory Accuracy.
Prerequisites
- An Entra ID tenant added on Admin > Identity Providers, with at least one finished sync. See Entra ID Setup.
- For delegated permission grants:
Directory.Read.All, approved for the GraphnAI app registration. - For Conditional Access coverage:
Policy.Read.All, approved for the GraphnAI app registration. - For PIM eligible roles: a tenant with Microsoft Entra ID P2 or Microsoft Entra ID Governance. The permission it uses,
RoleManagement.Read.Directory, is one GraphnAI already requires.
What Gets Detected
Abusable Microsoft Graph Application Permissions
A service principal can hold a Microsoft Graph application permission that escalates privilege. GraphnAI then adds a HasPermission edge from it to the Microsoft Graph service principal. The edge lists the permissions and carries a severity.
GraphnAI looks for these permissions:
| Permission | Severity | Why It Matters |
|---|---|---|
Application.ReadWrite.All |
Critical | Can change any application in the tenant, so an attacker can plant a lasting backdoor |
Directory.ReadWrite.All |
Critical | Full write access to the directory, a path to Global Administrator |
RoleManagement.ReadWrite.Directory |
Critical | Can assign any directory role, including Global Administrator |
AppRoleAssignment.ReadWrite.All |
High | Can grant any application permission to any principal |
GroupMember.ReadWrite.All |
High | Can add members to any group, including privileged groups |
ServicePrincipalEndpoint.ReadWrite.All |
High | Can change service principal configurations |
Group.ReadWrite.All |
Medium | Broad group management |
A service principal's abusable permissions share one HasPermission edge. Its severity is that of the most severe permission in the set.
[!NOTE] GraphnAI finds these in data every Entra ID sync already collects. They need no extra permission.
OAuth 2.0 Delegated Permission Grants
Each OAuth 2.0 permission grant becomes a HasPermission edge. Where it starts depends on who consented:
- Admin consent for all users (
AllPrincipals): from the app's service principal to the resource's service principal. The app can use these permissions for any user. - User consent: from the consenting user to the resource's service principal. The app acts on behalf of that one user.
GraphnAI rates each delegated scope:
| Severity | Example Scopes |
|---|---|
| Critical | Directory.ReadWrite.All, RoleManagement.ReadWrite.Directory, Application.ReadWrite.All |
| High | Mail.ReadWrite, Files.ReadWrite.All, Group.ReadWrite.All, User.ReadWrite.All, AppRoleAssignment.ReadWrite.All |
| Medium | Mail.Send, Calendars.ReadWrite, Contacts.ReadWrite |
| Low | User.Read, openid, profile, email |
A scope not in this list counts as Medium, so an unknown scope is never rated below that. A grant's edge carries the severity of its most severe scope, and its permissions list holds every scope in the grant.
To list the apps with admin consent for all users, open Identity Inventory and choose the NHI: Consent for all users preset.
Conditional Access Policy Coverage
With Policy.Read.All approved, each Entra ID sync reads your Conditional Access policies. For every policy that isn't disabled, GraphnAI adds an AppliedPolicy edge from each user and group the policy names to the policy.
This answers questions such as:
- Which users have no Conditional Access policy?
- Are privileged users covered by policies that require MFA?
- Which groups does a policy leave out?
A policy that targets All users gets no per-user edges, which would number in the thousands. Instead, the policy carries an appliesToAll property.
PIM Eligible Role Assignments
On a tenant with Microsoft Entra ID P2 or Microsoft Entra ID Governance, each Entra ID sync reads PIM eligible role assignments. These are roles a principal can activate on demand but doesn't hold right now.
GraphnAI adds an EligibleForRole edge from the principal to the role. Critical Junctions analysis follows it, because an attacker who takes over an account eligible for Global Administrator can activate the role. A HasRole edge is an active assignment, so the two show separately: what a principal holds, and what it could activate.
If Microsoft refuses the PIM request, because the tenant lacks the license or the permission, the sync continues without it. The Privileged Identity Management row on the coverage card shows why.
Guest User Flagging
Users whose userType is Guest in Entra ID get the property isGuest: true. It shows as Is guest in the user's detail panel. Guest flagging needs no extra permission.
Setting Up Conditional Access and PIM
Conditional Access coverage needs Policy.Read.All. PIM needs only the license.
Step 1: Add the Required Permission
The quickest way is Update the app registration on the Data collected from this tenant card. See Updating an existing app registration. To do it by hand:
- In the Microsoft Entra admin center, open App registrations.
- Select the GraphnAI app registration, named
GraphnAI Platformunless you chose another name. - Go to API permissions > Add a permission > Microsoft Graph > Application permissions.
- Add
Policy.Read.All. - Select Grant admin consent for [your tenant].
[!IMPORTANT] A Global Administrator or Privileged Role Administrator must grant admin consent. The permission does nothing until then.
Step 2: Trigger a Sync
- In GraphnAI, open Admin > Identity Providers as an Admin.
- Choose your Entra ID tenant from the provider menu.
- Select Sync now.
When the sync finishes, the Conditional Access policies row on the coverage card reads Collected.
Viewing This Data in the Graph
HasPermission Edges (Abusable App Permissions and Delegated Grants)
In the Graph Explorer, search for a service principal that holds sensitive Graph permissions. A HasPermission edge runs from it to the Microsoft Graph service principal. The label names one permission and adds a count for the rest, such as Application.ReadWrite.All +1. Select the edge to see every permission it carries. See Relationship Detail Drill-Down.
To see every service principal with abusable Graph permissions, focus the Microsoft Graph service principal. Its incoming HasPermission edges come from them.
EligibleForRole Edges (PIM)
An eligible role isn't active until the principal activates it, so the graph draws it as blocked: a dashed, dimmed slate line labeled Eligible for role (blocked). An active HasRole assignment is a solid line.
AppliedPolicy Edges (Conditional Access)
AppliedPolicy edges join users and groups to Conditional Access policies. They're drawn in the neutral gray the graph uses for edge types without a color of their own.
To see who a policy covers:
- Search for the policy by name.
- Focus the policy in the graph.
- Its incoming edges are the users and groups the policy names.
Guest Users
A guest user's detail panel lists Is guest. Identity Inventory doesn't filter on it.
How These Edges Affect Analysis
Over-Permission Analytics
HasPermission edges from abusable app permissions and delegated grants count toward the effective permission total of service principals and users. A service principal that holds Application.ReadWrite.All stands out as a finding in its peer group.
AppliedPolicy and EligibleForRole edges don't count as permissions.
Critical Junctions Analysis
The junction engine follows HasPermission and EligibleForRole edges when it works out attack paths to critical assets. A service principal with RoleManagement.ReadWrite.Directory can make itself a Global Administrator, so it adds to the junction score of every identity on a path to it.
The junction engine doesn't follow AppliedPolicy edges.
Risk Posture Dashboard
HasPermission edges from Entra ID count toward the over-permission findings on the Risk Posture Dashboard. A tenant with many over-consented apps shows more findings.
Troubleshooting
No abusable app permission edges appear after a sync
Cause: No service principal holds one of the listed permissions, or GraphnAI didn't find the Microsoft Graph service principal in the tenant.
Steps:
- Check the server log for
Found MS Graph service principal. If the line is missing, GraphnAI didn't find the Microsoft Graph service principal. This is rare. - Check that at least one app holds Graph permissions as application permissions. Delegated permissions show up as grants instead.
Delegated grant edges don't appear
Cause: Directory.Read.All isn't approved, grant collection is turned off, the read failed, or the tenant has no grants.
Steps:
- Open Admin > Identity Providers and check the Delegated permission grants row on the coverage card. Its badge and line say what's wrong.
- If a grant exists but has no edge, check that the consenting user or app's service principal was collected.
Conditional Access edges are missing after you added Policy.Read.All
Cause: Admin consent wasn't granted, or no sync has run since.
Steps:
- In the Microsoft Entra admin center, check that
Policy.Read.Allshows a green check and Granted for [your tenant]. - Select Sync now on Admin > Identity Providers.
- Check the Conditional Access policies row on the coverage card. Collected means the policies were read. Disabled policies get no edges.
PIM edges are missing
Cause: The tenant has no Microsoft Entra ID P2 or Microsoft Entra ID Governance license, or PIM collection is turned off.
Steps:
- Check the Privileged Identity Management row on the coverage card. Not on this license is expected for a tenant without P2 or Governance, and the sync still succeeds.
- Check the tenant's license in the Microsoft Entra admin center under Identity > Overview > License features.
- If the row reads Turned off, turn it back on in the Sync features list under Sync attributes, from the gear icon at the top of the page.
A guest user doesn't show Is guest
Cause: The user wasn't in the last sync, or changed to a guest after it.
Steps:
- Select Sync now on Admin > Identity Providers.
- When the sync finishes, open the user's detail panel and look for Is guest.
You see many more permission findings
Cause: Over-consented apps and broad delegated grants count as permissions. A tenant with many admin-consented apps or broad grants shows more over-permission findings.
Steps:
- In Identity Inventory, open the Service principals tab with the Over-permissioned preset to review app findings first.
- For each high-severity finding, open the graph and check which permissions it holds.
- Work with each app's owner to narrow its scopes.