Skip to content

AZ_ROLE_SCOPED_TO

Copy page

Summary

Forestall ACL Alias AZ_ROLE_SCOPED_TO
Entra ID (Azure AD) Alias Scope
Affected Object Types App Registrations, Service Principals
Exploitation Certainty Certain
Graph Permission / Role Application Administrator, Cloud Application Administrator, or custom Entra ID directory roles with scoped assignments

Description

AZ_ROLE_SCOPED_TO represents the scoping relationship for Entra ID directory role assignments. Roles like Application Administrator and Cloud Application Administrator can be assigned either tenant-wide or scoped to specific objects:

  • Tenant-scoped (/): Control over all app registrations and service principals in the tenant.
  • Object-scoped (/<objectId>): Control over only the specific app registration(s) or service principal(s) designated in the scope.

This distinction is critical for attack path analysis, as tenant-scoped assignments provide significantly broader control than object-scoped ones.

Identification

PowerShell

Enumerate Scoped Role Assignments

Import-Module Microsoft.Graph.Identity.DirectoryManagement
Connect-MgGraph -Scopes "RoleManagement.Read.Directory", "Directory.Read.All"
function Get-ScopedRoleAssignments {
$allAssignments = [System.Collections.Generic.List[PSCustomObject]]::new()
# Build a role definition lookup (Graph only allows expanding one property per query)
$roleDefinitions = @{}
Get-MgRoleManagementDirectoryRoleDefinition -All | ForEach-Object {
$roleDefinitions[$_.Id] = $_.DisplayName
}
# Get all directory role assignments with principal expanded
$roleAssignments = Get-MgRoleManagementDirectoryRoleAssignment -All -ExpandProperty "principal"
foreach ($ra in $roleAssignments) {
$scope = $ra.DirectoryScopeId
$isScoped = $scope -ne "/"
$principalName = $ra.Principal.AdditionalProperties.displayName
$principalType = if ($ra.Principal.AdditionalProperties.'@odata.type') {
$ra.Principal.AdditionalProperties.'@odata.type' -replace '^#microsoft\.graph\.', ''
} else { 'Unknown' }
$roleName = $roleDefinitions[$ra.RoleDefinitionId]
$allAssignments.Add([PSCustomObject]@{
RoleName = $roleName
RoleId = $ra.RoleDefinitionId
PrincipalName = $principalName
PrincipalId = $ra.PrincipalId
PrincipalType = $principalType
Scope = $scope
IsScoped = $isScoped
AssignmentId = $ra.Id
})
}
$allAssignments
}
$assignments = Get-ScopedRoleAssignments
# Show all scoped (non-tenant-wide) assignments
Write-Host "`n=== Object-Scoped Role Assignments ===" -ForegroundColor Yellow
$assignments | Where-Object { $_.IsScoped -eq $true } |
Sort-Object RoleName, PrincipalName |
Format-Table RoleName, PrincipalName, PrincipalType, Scope -AutoSize
# Show tenant-wide assignments for scopeable roles
$scopeableRoles = @("Application Administrator", "Cloud Application Administrator")
Write-Host "`n=== Tenant-Wide Assignments for Scopeable Roles ===" -ForegroundColor Yellow
$assignments | Where-Object { $_.IsScoped -eq $false -and $_.RoleName -in $scopeableRoles } |
Sort-Object RoleName, PrincipalName |
Format-Table RoleName, PrincipalName, PrincipalType -AutoSize
# Export all
$assignments | Export-Csv -Path ".\ScopedRoleAssignments.csv" -NoTypeInformation -Encoding UTF8
Write-Host "`nTotal assignments: $($assignments.Count)"
Write-Host "Object-scoped assignments: $(($assignments | Where-Object IsScoped).Count)"
Write-Host "Tenant-wide assignments: $(($assignments | Where-Object { -not $_.IsScoped }).Count)"

Resolve Scoped Target Objects

# For each scoped assignment, resolve the target object
function Resolve-ScopedTarget {
param([string]$DirectoryScopeId)
if ($DirectoryScopeId -eq "/") {
return [PSCustomObject]@{ Type = "Tenant"; Name = "Entire Tenant"; Id = "/" }
}
# Scoped assignments use format: /<objectId> or /administrativeUnits/<auId>
$objectId = $DirectoryScopeId.TrimStart('/')
# Try as Application
try {
$app = Get-MgApplication -ApplicationId $objectId -ErrorAction Stop
return [PSCustomObject]@{ Type = "Application"; Name = $app.DisplayName; Id = $app.Id }
} catch {}
# Try as Service Principal
try {
$sp = Get-MgServicePrincipal -ServicePrincipalId $objectId -ErrorAction Stop
return [PSCustomObject]@{ Type = "ServicePrincipal"; Name = $sp.DisplayName; Id = $sp.Id }
} catch {}
# Try as Administrative Unit
if ($DirectoryScopeId -match "/administrativeUnits/(.+)") {
try {
$au = Get-MgDirectoryAdministrativeUnit -AdministrativeUnitId $Matches[1] -ErrorAction Stop
return [PSCustomObject]@{ Type = "AdministrativeUnit"; Name = $au.DisplayName; Id = $au.Id }
} catch {}
}
return [PSCustomObject]@{ Type = "Unknown"; Name = $DirectoryScopeId; Id = $DirectoryScopeId }
}
# Example: Resolve all scoped targets
$scopedAssignments = $assignments | Where-Object { $_.IsScoped }
foreach ($sa in $scopedAssignments) {
$target = Resolve-ScopedTarget -DirectoryScopeId $sa.Scope
Write-Host "$($sa.RoleName) | $($sa.PrincipalName) -> $($target.Type): $($target.Name)" -ForegroundColor Cyan
}

Exploitation

Related Attack Paths:

  • AZ_APP_ADMIN - Application Administrator role; if tenant-scoped, applies to all apps. If object-scoped, only applies to specific apps.
  • AZ_CLOUD_APP_ADMIN - Cloud Application Administrator role; same scoping behavior as Application Administrator.
  • AZ_ADD_SECRET - Principals with scoped Application/Cloud App Admin roles can add secrets to the scoped app.
  • AZ_ADD_OWNER - Scoped role holders can add owners to the target app/SP.

The abuse potential depends entirely on whether the role is scoped to the tenant or to individual objects:

Scope Impact Example
Tenant-wide (/) Full control over all app registrations and service principals in the tenant Application Administrator scoped to the directory can add credentials to any app, modify any SP, and escalate via high-privilege apps
Object-scoped (/<objectId>) Control over only the specific app registration(s) or service principal(s) in scope Application Administrator scoped to a single app can only add credentials/modify that one app

Mitigation

This is a structural relationship (not directly abusable) indicating role assignment scope. Mitigation:

  • Prefer object-scoped over tenant-wide assignments (least privilege principle).
  • Audit tenant-wide assignments and narrow to specific objects where possible.
  • Regularly review and remove unnecessary assignments.

Detection

Use the Microsoft Entra admin center:

  1. Open Microsoft Entra ID -> Audit logs.
  2. Filter Activity for:
    • Add member to role
    • Add eligible member to role
    • Remove member from role
  3. Review Initiated by (actor), Target, Date, Status, and role scope details for unexpected scoped role changes.
  4. Open Roles & administrators and review the affected role assignment scope.
  5. Use Manage view -> Edit columns if any of those fields are hidden.

References

Was this page helpful?

Thank you for your feedback.