Agent - Identity / OAuth scope escalation in AuditLogs
Agent Identity O Auth Escalation
Query
let lookback = 1d;
let agentMap =
_GetWatchlist('AgentIdentityMap')
| project AgentName = tostring(column_ifexists('AgentName', '')),
AppId = tolower(tostring(column_ifexists('AppId', ''))),
ObjectId = tolower(tostring(column_ifexists('ObjectId', ''))),
Upn = tolower(tostring(column_ifexists('Upn', '')));
let agentKeys =
agentMap
| mv-expand Key = pack_array(AppId, ObjectId, Upn) to typeof(string)
| where isnotempty(Key)
| distinct AgentName, Key;
AuditLogs
| where TimeGenerated > ago(lookback)
| extend
OperationName_ = tostring(column_ifexists('OperationName', '')),
InitiatedBy_ = column_ifexists('InitiatedBy', dynamic({})),
TargetResources_ = column_ifexists('TargetResources', dynamic([])),
Result_ = tostring(column_ifexists('Result', '')),
ResultReason_ = tostring(column_ifexists('ResultReason', '')),
CorrelationId_ = tostring(column_ifexists('CorrelationId', ''))
| where OperationName_ has_any (
"Consent to application", "Add app role assignment",
"Add delegated permission grant", "Add OAuth2PermissionGrant",
"Add member to role", "Add eligible member to role",
"Add service principal credentials", "Update application - Certificates and secrets management",
"Add application", "Update application", "Add owner to service principal",
"Update service principal")
| extend
ActorSpn = tolower(tostring(InitiatedBy_.app.servicePrincipalId)),
ActorApp = tolower(tostring(InitiatedBy_.app.appId)),
ActorUser = tolower(tostring(InitiatedBy_.user.userPrincipalName))
| mv-apply T = TargetResources_ on (
extend TargetId = tolower(tostring(T.id)), TargetName = tostring(T.displayName)
| summarize TargetIds = make_set(TargetId, 16), TargetNames = make_set(TargetName, 16)
)
| extend ActorKeys = pack_array(ActorSpn, ActorApp, ActorUser)
| extend MatchActor = set_has_element(todynamic(toscalar(agentKeys | summarize make_set(Key))), ActorSpn)
or set_has_element(todynamic(toscalar(agentKeys | summarize make_set(Key))), ActorApp)
or set_has_element(todynamic(toscalar(agentKeys | summarize make_set(Key))), ActorUser)
| extend MatchTarget = set_intersect(todynamic(TargetIds), todynamic(toscalar(agentKeys | summarize make_set(Key))))
| where MatchActor or array_length(MatchTarget) > 0
| extend AgentRole = case(MatchActor and array_length(MatchTarget) > 0, "ActorAndTarget",
MatchActor, "AgentIsActor",
"AgentIsTarget")
| project
TimeGenerated, OperationName = OperationName_, AgentRole,
Actor = coalesce(ActorSpn, ActorApp, ActorUser),
TargetNames, TargetIds, Result = Result_, ResultReason = ResultReason_, CorrelationId = CorrelationId_
| order by TimeGenerated descExplanation
This KQL query is designed to detect potential security risks related to identity and permission changes in Azure Active Directory (Azure AD). Here's a simplified breakdown of what the query does:
-
Purpose: The query aims to identify suspicious activities involving Azure AD agents that could indicate privilege escalation, persistence, or identity abuse. It focuses on changes like OAuth consent grants, app role assignments, directory role memberships, and credential rotations.
-
Agent Mapping: It uses a watchlist called
AgentIdentityMapto map known agent identities. This map includes details like agent names, application IDs, object IDs, and user principal names, all converted to lowercase for consistency. -
Audit Logs Filtering: The query examines Azure AD
AuditLogsfor the past day (lookback = 1d). It filters logs for specific operations that could indicate privilege changes, such as adding app roles, granting permissions, or updating credentials. -
Actor and Target Identification: It extracts information about who initiated the action (actor) and the target resources affected. The query checks if either the actor or the target matches any known agent identity from the watchlist.
-
Match Detection: It flags events where either the actor or the target is a known agent identity. This helps identify scenarios where an agent might be escalating its own privileges or someone else is granting new permissions to an agent.
-
Role Classification: The query classifies the role of the agent in the event as either "AgentIsActor," "AgentIsTarget," or "ActorAndTarget," depending on whether the agent is the initiator, the target, or both.
-
Output: The results include details like the time of the event, operation name, agent role, actor identity, target names and IDs, result, reason for the result, and a correlation ID for tracking.
-
Security Tactics and Techniques: The query is associated with security tactics like Privilege Escalation and Persistence, and techniques such as T1098 (Account Manipulation), T1528 (Steal Application Access Token), and T1556 (Modify Authentication Process).
-
Tags: It includes tags for categorization, such as Sentinel-As-Code, Custom, Foundry, and AI.
Overall, this query helps security teams monitor and respond to potential unauthorized changes in Azure AD that could compromise security.
Details

David Alonso
Released: June 8, 2026
Tables
Keywords
Operators
Tactics