A single Microsoft Graph application permission can let a service principal read every mailbox, grant itself more permissions or assign Global Administrator, with no signed-in user, no MFA and no Conditional Access prompt. These grants accumulate quietly: a vendor integration asks for Directory.ReadWrite.All because it was easier, a test app keeps Mail.ReadWrite after the project ends, an automation account is given AppRoleAssignment.ReadWrite.All to "fix consent". This guide shows how to list every application permission granted in a tenant from read-only queries, rank them into risk tiers using what each permission actually allows, find the owners and usage, and remove or scope them without breaking the integration. It is for Entra administrators, identity security engineers and NHI programme owners. For how consent works in general see the Entra ID Applications and Consent Guide.
Key takeaways
- Application permissions are app roles. Each grant is an appRoleAssignment from the client service principal to the Microsoft Graph service principal (appId 00000003-0000-0000-c000-000000000000), so one query on that resource lists every Graph application permission in the tenant.
- Some permissions are a path to Global Administrator. RoleManagement.ReadWrite.Directory manages directory role membership, AppRoleAssignment.ReadWrite.All grants application permissions to any API, and Application.ReadWrite.All manages other apps and service principals, including their credentials.
- "Read" is not low risk. Mail.Read reads mail in all mailboxes; Files.ReadWrite.All and Sites.FullControl.All reach every site collection. Data permissions are the breach impact, not a lesser tier.
- Graph is not the only source. Service principals also get power from Entra directory roles, Azure RBAC, ownership of other apps, Exchange RBAC for Applications and other APIs; the inventory must cover them.
- Scope before you revoke. Sites.Selected and Exchange RBAC for Applications let an integration keep working on the data it needs, but the unscoped Entra grant must be removed or the scoping has no effect.
When you need this
- Baseline: you have never inventoried application permissions, or the last review was a spreadsheet of app names.
- Supplier incident: a vendor holding credentials to your tenant is compromised and you must know what its app can reach. In the Commvault Metallic breach customers were told to revalidate the permissions granted to the affected app registrations.
- Threat hunting: you are checking for attacker-created or attacker-modified apps. In the Microsoft Midnight Blizzard breach a legacy test OAuth app with elevated access was used to grant the Exchange Online full_access_as_app role, giving mailbox access that password resets did not cut off.
- Access review or audit: evidence that non-human privileged access is known, owned and justified.
Before you start
| Requirement | Detail |
|---|---|
| Read-only discovery | Graph scope Application.Read.All (least privileged for listing appRoleAssignedTo); Directory Readers or Global Reader for delegated use |
| Usage evidence | Read access to Entra sign-in logs (service principal sign-ins) and audit logs, ideally in Log Analytics |
| Removal | Cloud Application Administrator or Application Administrator; Graph scope AppRoleAssignment.ReadWrite.All for scripted removal |
| Granting replacements | Only Privileged Role Administrator and Global Administrator can consent to application permissions, per Microsoft's permissions overview |
| Exchange scoping | Organization Management role group plus Exchange Administrator for RBAC for Applications |
Step-by-step
Steps 1 to 5 are read-only. Step 6 adds scoped permissions. Step 7 removes grants and is the only disruptive step.
- List every Graph application permission in the tenant. Query the Graph service principal's appRoleAssignedTo collection and resolve each appRoleId to its name from the same object's appRoles:
The REST equivalent is GET https://graph.microsoft.com/v1.0/servicePrincipals(appId='00000003-0000-0000-c000-000000000000')/appRoleAssignedTo. Resolving names at run time avoids hard-coding permission GUIDs. CreatedDateTime shows when each grant was made, which helps spot recent additions.Connect-MgGraph -Scopes "Application.Read.All" $graph = Get-MgServicePrincipal -Filter "appId eq '00000003-0000-0000-c000-000000000000'" -Property Id,AppRoles $roles = @{}; $graph.AppRoles | ForEach-Object { $roles[$_.Id] = $_.Value } $grants = Get-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $graph.Id -All | Where-Object PrincipalType -eq 'ServicePrincipal' | Select-Object PrincipalDisplayName, PrincipalId, @{n='Permission';e={$roles[$_.AppRoleId]}}, CreatedDateTime $grants | Export-Csv graph_app_permissions.csv -NoTypeInformation - Repeat for other resource APIs. Graph is the main target, but run the same loop against every resource service principal that exposes app roles, in particular Office 365 Exchange Online (where full_access_as_app lives) and SharePoint. A simple approach is to loop over all service principals with a non-empty AppRoles collection.
- Tier each grant. Match the Permission column against the tier table below. Add the delegated equivalents from oauth2PermissionGrants where ConsentType is AllPrincipals, since admin-consented delegated grants on behalf of all users are flagged as high severity in Microsoft's application security operations guide.
- Enrich with owner, publisher and credentials. For each service principal in tier 0 or tier 1, record AppOwnerOrganizationId (your tenant or a third party), owners (Get-MgServicePrincipalOwner and the app registration's owners), the credentials it holds, and whether it uses secrets or federation. An unowned tier 0 app with a client secret is the top finding in most tenants.
- Check other privilege paths and usage. List directory role assignments to service principals (the audit activity "Add member to role" with a service principal target) and Azure RBAC assignments; see the Azure RBAC and Service Principals Guide. Then use service principal sign-in logs to find whether the app signs in at all, from where, and to which resource. Unused apps are covered in How to find and remove stale service principals in Entra ID.
- Add the scoped replacement first. For SharePoint, grant Sites.Selected and give the app access only to named site collections. For mail, assign an Exchange application role with a resource scope:
Microsoft notes that changes take 30 minutes to 2 hours to apply, and that Test-ServicePrincipalAuthorization excludes permissions granted in Entra.New-ServicePrincipal -AppId <appId> -ObjectId <enterprise app object id> -DisplayName "Invoice mailbox reader" New-ManagementScope -Name "Invoice mailboxes" -RecipientRestrictionFilter "CustomAttribute1 -eq 'invoices'" New-ManagementRoleAssignment -App <appId> -Role "Application Mail.Read" -CustomResourceScope "Invoice mailboxes" Test-ServicePrincipalAuthorization -Identity <appId> -Resource [email protected] - Remove the broad grant (disruptive). In the Entra admin center go to Enterprise apps, the app, Permissions, Admin consent, and choose Revoke permission; or call Remove-MgServicePrincipalAppRoleAssignedTo, or DELETE /servicePrincipals/{resource-id}/appRoleAssignedTo/{assignment-id}. For Exchange this step is mandatory: the union of an unscoped Entra Mail.Read grant and a scoped RBAC grant results in no effective scoping. Also remove the permission from the app registration's requiredResourceAccess, otherwise an administrator can simply re-consent.
Risk tiers for Graph application permissions
The descriptions below are Microsoft's own wording for the application (app-only) form of each permission. The tiering is NHI Mgmt Group's, based on what the description allows.
| Tier | Permission | What Microsoft says it allows (app-only) | Why it is in this tier |
|---|---|---|---|
| 0: tenant takeover | RoleManagement.ReadWrite.Directory | Read and manage RBAC settings for the directory, including directory role membership | Can add any principal, including itself, to privileged directory roles |
| 0 | AppRoleAssignment.ReadWrite.All | Manage permission grants for application permissions to any API, including Microsoft Graph | Can grant itself any other permission in this table |
| 0 | Application.ReadWrite.All | Create, read, update and delete applications and service principals | Can add credentials to a more privileged app and sign in as it |
| 0 | RoleAssignmentSchedule.ReadWrite.Directory; PrivilegedAccess.ReadWrite.AzureADGroup | Manage policies for privileged role assignments; manage time-based assignment and just-in-time elevation of groups | Changes who can activate privileged roles and groups |
| 1: identity control | Policy.ReadWrite.ConditionalAccess; Policy.ReadWrite.AuthenticationMethod | Read and write Conditional Access policies; authentication method policies | Can switch off the controls that protect admins |
| 1 | UserAuthenticationMethod.ReadWrite.All | Read and write authentication methods of all users | Can register a method on another user's account |
| 1 | User.ReadWrite.All; Group.ReadWrite.All; Directory.ReadWrite.All | Update user profiles; create, update and delete groups and memberships; read and write directory data | Microsoft notes User.ReadWrite.All can update users in privileged roles; group writes can reach role-assignable or access-granting groups |
| 1 | Domain.ReadWrite.All | Add, verify and remove domains | Domain and federation changes affect sign-in for the whole tenant |
| 1 | Application.ReadWrite.OwnedBy | Create apps and fully manage the apps it owns, including secrets | Bounded by ownership, so its risk equals the most privileged app it owns |
| 2: bulk data | Mail.Read; Mail.ReadWrite; Mail.Send | Read, or create, update and delete, mail in all mailboxes; send mail as any user | Whole-tenant mailbox access and impersonation; scope with Exchange RBAC for Applications |
| 2 | Files.ReadWrite.All; Sites.FullControl.All | All files in all site collections; full control of all site collections | Whole-tenant document access; replace with Sites.Selected |
| 3: read directory | Directory.Read.All | Highest privileged read-only permission for Entra resources (permissions overview) | Reconnaissance value: maps admins, groups and apps |
Treat this as a starting list, not the full catalogue. Any permission ending in ReadWrite.All on a security, policy or role resource deserves tier 1 review until you have read its description in the permissions reference.
Prioritising and deciding
| Finding | Decision |
|---|---|
| Tier 0 grant, third-party app | Ask the supplier for the operations it performs; tier 0 is rarely justified for a SaaS integration. Escalate as a risk acceptance if they cannot reduce it |
| Tier 0 grant, in-house automation | Keep only if the automation is itself tier 0 (for example, an identity governance engine); require federation instead of secrets, an owner, and alerting on every sign-in from a new IP |
| Tier 2 mail or files grant used for a few mailboxes or sites | Add the scoped grant (Exchange RBAC for Applications or Sites.Selected), test, then revoke the tenant-wide grant |
| Any tier with no sign-ins in 90 days | Revoke; the stale app process applies |
| Grant created recently, outside change management | Treat as a potential incident until explained |
Small tenants usually have a handful of tier 0 and tier 1 grants and can review them by hand. Large tenants should schedule the export, store it, and diff each run, alerting on any new tier 0 or tier 1 grant rather than relying on periodic review.
Verify it worked
- Re-run the export: the revoked grant no longer appears for the service principal; replication delays can apply to recently changed assignments.
- Integration health: service principal sign-ins continue with success results, and the application's own logs show no permission errors over a full business cycle.
- Exchange scoping: Test-ServicePrincipalAuthorization returns InScope True for an intended mailbox and False for one outside the scope.
- Audit trail: the audit log shows the removal, linked to your change ticket.
Rollback and common errors
- Integration breaks after revocation: Microsoft documents that revoked permissions can be restored (Restore permissions granted to applications). Restore, then plan the scoped replacement properly.
- Scoped mail grant has no effect: the unscoped Entra Mail.* consent is still in place. Remove it.
- Permission comes back: it is still in the app's requested permissions and was re-consented. Update the app registration.
- Revoked in the portal but still listed: the portal can revoke admin-consented permissions only; user-consented delegated grants need Graph or PowerShell.
Common failure patterns
- Reviewing only delegated consent: consent reviews focus on user consent prompts while app-only grants, which need no user at all, go unchecked.
- Trusting the app name: test, legacy and "temporary" apps keep their grants, as Midnight Blizzard showed.
- Ignoring indirect escalation: an app with Application.ReadWrite.All looks like app management, but it can add a secret to any tier 0 app and become it.
- Scoping without removing: adding Exchange RBAC for Applications while leaving the Entra grant creates the impression of control with none of the effect.
- Graph only: directory roles, Azure RBAC and other APIs are left out of the inventory.
Detection and measurement
Microsoft's application security operations guide rates these audit events high severity and provides Sentinel templates (ServicePrincipalAssignedAppRoleWithSensitiveAccess, ServicePrincipalAssignedPrivilegedRole, MailPermissionsAddedToApplication, NewAppOrServicePrincipalCredential):
AuditLogs
| where OperationName in ("Add app role assignment to service principal",
"Add delegated permission grant", "Add member to role")
| extend Target = tostring(TargetResources[0].displayName)
| project TimeGenerated, OperationName, Target,
Actor = tostring(InitiatedBy.user.userPrincipalName),
ActorApp = tostring(InitiatedBy.app.displayName), TargetResources
- Number of service principals holding tier 0 permissions (target: small, known, each with a named owner).
- Tier 0 and tier 1 apps using client secrets rather than certificates or federation.
- Tenant-wide Mail.* and Files/Sites grants replaced by scoped grants.
- New tier 0 or tier 1 grants per month outside change management (target zero).
- Time from grant to review for new high-privilege grants.
Framework mapping
| Framework | Reference | Relevance |
|---|---|---|
| NIST SP 800-53 Rev 5 | AC-6 Least Privilege; AC-6(7) Review of User Privileges; AC-2 Account Management | Tiering, scoping and periodic review of app privileges |
| NIST CSF 2.0 | PR.AA-05 | Access permissions defined, managed and reviewed with least privilege |
| MITRE ATT&CK v20 | T1098.003 Additional Cloud Roles; T1098.001 Additional Cloud Credentials | Granting roles or credentials to apps for persistence and escalation |
| MITRE ATT&CK v20 | T1114.002 Remote Email Collection; T1550.001 Application Access Token | What tier 2 mail permissions enable when abused |
Practitioner checklist
- Export appRoleAssignedTo for Microsoft Graph and every other resource service principal with app roles.
- Resolve permission names at run time from appRoles rather than hard-coded GUIDs.
- Tier every grant and add admin-consented AllPrincipals delegated grants.
- Record owner, publisher tenant and credential type for tier 0 and tier 1 apps.
- Include directory role and Azure RBAC assignments to service principals.
- Replace tenant-wide mail and file grants with Exchange RBAC for Applications or Sites.Selected, then remove the Entra grant.
- Remove revoked permissions from the app registration's requested permissions.
- Alert on new app role assignments, delegated grants and role memberships for service principals.
Standards and references
- Microsoft Learn: Overview of Microsoft Graph permissions
- Microsoft Learn: Microsoft Graph permissions reference
- Microsoft Graph: List appRoleAssignments granted for a service principal
- Microsoft Learn: Review and revoke permissions granted to applications
- Microsoft Learn: Microsoft Entra security operations guide for applications
- Microsoft Learn: Role Based Access Control for Applications in Exchange Online
Related NHI Mgmt Group resources: Entra ID Applications and Consent Guide · Consent Phishing and Illicit OAuth Grants Guide · Azure RBAC and Service Principals Guide · Azure Entra Client Secrets Security Guide