Query Details
// Hunt : Workload Identity - User Risk Event Timeline Correlated with SP Privilege Changes (30d)
// Purpose : Builds a chronological timeline pairing each AADUserRiskEvents entry with all
// SP privilege escalation or credential operations performed by the same user within
// 72 hours before or after the risk event. Use to reconstruct the attack chain:
// what was done to workload identities before, during, and after account compromise.
// Includes time-delta annotations to identify suspicious proximity between risk
// detection and SP modification.
// Tables : AADUserRiskEvents, AuditLogs
// Period : P30D
// Tactics : CredentialAccess, Persistence, PrivilegeEscalation, LateralMovement
// MITRE : T1098.001, T1078.004, T1098.003
//==========================================================================================
let LookbackDays = 30d;
let ProximityHours = 72;
let HighImpactOps = dynamic([
"Add service principal credentials",
"Remove service principal credentials",
"Add password to service principal",
"Add key credential to service principal",
"Add owner to service principal",
"Add owner to application",
"Add app role assignment to service principal",
"Add delegated permission grant",
"Consent to application",
"Add OAuth2PermissionGrant",
"Add member to role",
"Add application",
"Add service principal"
]);
// All user risk events in the window
let RiskEvents = union isfuzzy=true
AADUserRiskEvents,
(datatable(UserId:string, UserPrincipalName:string, RiskEventType:string,
RiskLevel:string, DetectedDateTime:datetime)[])
| where DetectedDateTime > ago(LookbackDays)
| project
UserId,
UserPrincipalName,
RiskEventType,
RiskLevel,
RiskDetected = DetectedDateTime;
// SP lifecycle operations in the same window
let SPOps = AuditLogs
| where TimeGenerated > ago(LookbackDays)
| where OperationName has_any (HighImpactOps)
| where Result =~ "success"
| where isnotempty(tostring(InitiatedBy.user.id))
| extend InitiatorUserId = tostring(InitiatedBy.user.id)
| extend InitiatorUPN = tostring(InitiatedBy.user.userPrincipalName)
| extend TargetId = tostring(TargetResources[0].id)
| extend TargetName = tostring(TargetResources[0].displayName)
| extend InitiatorIP = tostring(InitiatedBy.user.ipAddress)
| project
InitiatorUserId, InitiatorUPN, OperationName,
TargetId, TargetName, InitiatorIP,
AuditTime = TimeGenerated;
// Cross-join and compute time delta between risk detection and SP operation
RiskEvents
| join kind=inner SPOps on $left.UserId == $right.InitiatorUserId
| extend DeltaHours = datetime_diff("hour", AuditTime, RiskDetected)
| where abs(DeltaHours) <= ProximityHours
| extend Proximity = case(
DeltaHours < 0, strcat("Before risk by ", tostring(abs(DeltaHours)), "h"),
DeltaHours == 0, "Same hour as risk detection",
strcat("After risk by ", tostring(DeltaHours), "h"))
| extend Phase = case(
DeltaHours < -24, "Pre-detection (>24h before)",
DeltaHours < 0, "Pre-detection (<24h before)",
DeltaHours == 0, "Simultaneous",
DeltaHours <= 6, "Post-detection (<6h)",
DeltaHours <= 24, "Post-detection (6-24h)",
"Post-detection (24-72h)")
| project
UserPrincipalName, UserId, RiskEventType, RiskLevel, RiskDetected,
OperationName, TargetName, TargetId, InitiatorIP,
AuditTime, DeltaHours, Proximity, Phase
| order by UserPrincipalName asc, AuditTime asc
This query is designed to help security analysts understand potential security incidents involving Azure Active Directory (AAD) users and service principals (SPs). Here's a simplified breakdown of what the query does:
Purpose: The query aims to create a timeline that links user risk events with any privilege changes or credential operations on service principals performed by the same user within a 72-hour window before or after the risk event. This helps in reconstructing the sequence of actions taken during a potential account compromise.
Data Sources: It uses two main data sources:
AADUserRiskEvents: Logs of risk events associated with AAD users.AuditLogs: Logs of operations performed on service principals.Time Frame: The query looks at data from the last 30 days.
Operations of Interest: It focuses on specific high-impact operations related to service principals, such as adding or removing credentials, adding roles, or granting permissions.
Process:
Output: The result is a timeline that shows:
Use Case: This timeline helps analysts identify suspicious activities and understand the sequence of events in potential security incidents, aiding in the investigation and response process.

David Alonso
Released: April 21, 2026
Tables
Keywords
Operators