Added Sensitive Api Permissions
Query
// Added Sensitive API Permissions from unprivileged user
// Modified version from "Admin promotion after Role Management Application Permission Grant" (f80d951a-eddc-4171-b9d0-d616bb83efdc) and "Service Principal Assigned App Role With Sensitive Access" (dd78a122-d377-415a-afe9-f22e08d2112c)
let SensitiveMsGraphPermissions = externaldata(EAMTierLevelName: string, Category: string, AppRoleDisplayName: string)["https://raw.githubusercontent.com/Cloud-Architekt/AzurePrivilegedIAM/main/Classification/Classification_MsGraphAppRoles.json"] with(format='multijson');
AuditLogs
| where TimeGenerated >ago(30d)
| where LoggedByService =~ "Core Directory"
| where Category =~ "ApplicationManagement"
| where AADOperationType =~ "Assign"
| where OperationName == "Add app role assignment to service principal"
| where Result =~ "success"
| mv-expand TargetResources
| mv-expand TargetResources.modifiedProperties
| extend displayName_ = tostring(TargetResources_modifiedProperties.displayName)
| where displayName_ =~ "AppRole.Value"
| extend AppRole = tostring(parse_json(tostring(TargetResources_modifiedProperties.newValue)))
| extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))
| extend InitiatingUserOrAppId = iff(isnotempty(InitiatedBy.user.id),tostring(InitiatedBy.user.id), tostring(InitiatedBy.app.id))
| extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))
| extend UserAgent = iff(AdditionalDetails[0].key == "User-Agent",tostring(AdditionalDetails[0].value),"")
| extend AddedPermission = replace_string(tostring(TargetResources_modifiedProperties.newValue),'"','')
| join kind=inner ( SensitiveMsGraphPermissions | project AddedPermissionClassification = EAMTierLevelName, AddedPermissionCategory = Category, AppRoleDisplayName ) on $left.AddedPermission == $right.AppRoleDisplayName
| mv-expand TargetResources.modifiedProperties | where TargetResources_modifiedProperties.displayName == "ServicePrincipal.ObjectID" | extend ServicePrincipalObjectID = replace_string(tostring(TargetResources_modifiedProperties.newValue),'"','')
| mv-expand TargetResources.modifiedProperties | where TargetResources_modifiedProperties.displayName == "ServicePrincipal.DisplayName" | extend ServicePrincipalDisplayName = replace_string(tostring(TargetResources_modifiedProperties.newValue),'"','')
| mv-expand TargetResources.modifiedProperties | where TargetResources_modifiedProperties.displayName == "ServicePrincipal.AppId" | extend ServicePrincipalAppId = replace_string(tostring(TargetResources_modifiedProperties.newValue),'"','')
| join kind=inner (
PrivilegedEAM_CL
| where TimeGenerated > ago(14d)
| summarize arg_max(TimeGenerated, *) by ObjectId
| extend InitiatingUserOrAppClassification = iff(isnotempty(parse_json(Classification)), parse_json(Classification), "UserAccess")
| project ObjectId, ObjectAdminTierLevel, ObjectAdminTierLevelName, InitiatingUserOrAppClassification
) on $left.InitiatingUserOrAppId == $right.ObjectId
| where parse_json(tostring(parse_json(InitiatingUserOrAppClassification))) !contains AddedPermissionClassification and parse_json(tostring(parse_json(InitiatingUserOrAppClassification))) !contains "ControlPlane"
| project-reorder OperationName, ServicePrincipalObjectID, ServicePrincipalDisplayName, ServicePrincipalAppId, InitiatingUserOrApp, InitiatingUserOrAppId, InitiatingIpAddress, InitiatingUserOrAppClassification, UserAgent, AddedPermission, AddedPermissionClassification, AddedPermissionCategoryExplanation
This query is designed to identify and analyze instances where sensitive Microsoft Graph API permissions have been added by users or applications that are not privileged. Here's a simplified breakdown of what the query does:
-
Load Sensitive Permissions Data: It starts by loading a list of sensitive Microsoft Graph API permissions from an external JSON file hosted on GitHub.
-
Filter Audit Logs: It filters Azure Active Directory (AAD) audit logs from the past 30 days to find successful operations where an application role was assigned to a service principal. This is specifically for operations logged by the "Core Directory" service under the "ApplicationManagement" category.
-
Extract Details: The query extracts details about the operation, including the name of the role assigned, the user or application that initiated the action, their IP address, and user agent.
-
Join with Sensitive Permissions: It joins the filtered audit logs with the sensitive permissions data to identify if the added permission is classified as sensitive.
-
Service Principal Details: It extracts additional details about the service principal involved in the operation, such as its Object ID, Display Name, and App ID.
-
Check Privileged Access: The query checks if the user or application that initiated the action has privileged access by joining with another dataset (
PrivilegedEAM_CL) that contains information about privileged roles. It ensures that the initiating user or app does not have a classification that matches the added permission classification or "ControlPlane". -
Output: Finally, it organizes the output to display relevant information such as the operation name, service principal details, initiating user or app details, and the classification and category of the added permission.
In essence, this query helps identify potentially unauthorized or risky assignments of sensitive permissions by non-privileged users or applications, which could indicate a security concern.
Details

Thomas Naunheim
Released: June 8, 2026
Tables
Keywords
Operators