Query Details
let query_frequency = 5m;
let query_period = 2d;
AADUserRiskEvents
| where TimeGenerated > ago(query_period)
| where Source == "IdentityProtection" and RiskEventType == "leakedCredentials"
| summarize FirstTimeGenerated = min(TimeGenerated), arg_max(TimeGenerated, *) by Id
| where FirstTimeGenerated > ago(query_frequency)
| project
//TimeGenerated,
ActivityDateTime,
DetectedDateTime,
Source,
Activity,
DetectionTimingType,
UserDisplayName,
UserPrincipalName,
UserId,
//IpAddress,
//RequestId,
//CorrelationId,
TokenIssuerType,
RiskEventType,
RiskDetail,
RiskLevel,
RiskState,
AdditionalInfo,
Id
| extend AltAlertLink = strcat("https://entra.microsoft.com/#blade/Microsoft_AAD_IAM/RiskDetectionsBlade/riskState~/[]/userId/", UserId, "/riskLevel/[]/daysBack/90")// Someone wrote "90s" incorrectly in Defender XDR portal
| join kind=leftouter (
SecurityAlert
| where ProviderName == "IPC" and ProductName == "Azure Active Directory Identity Protection" and AlertType == "LeakedCredentials"
| summarize arg_max(TimeGenerated, *) by VendorOriginalId
| project
AlertName,
AlertSeverity,
Description,
AlertStatus = Status,
Entities,
ExtendedProperties,
VendorName,
ProviderName,
ProductName,
ProductComponentName,
RemediationSteps,
Tactics,
Techniques,
SubTechniques,
VendorOriginalId,
SystemAlertId,
CompromisedEntity,
AlertLink
) on $left.Id == $right.VendorOriginalId
| extend AlertLink = coalesce(AlertLink, AltAlertLink)
| where case(
AlertStatus == "Resolved" and tostring(todynamic(ExtendedProperties)["State"]) == "Closed", false,
//RiskState == "dismissed" and RiskDetail == "aiConfirmedSigninSafe", false,
RiskState == "remediated" and RiskDetail == "userChangedPasswordOnPremises", false,
true
)
This query is designed to analyze and correlate user risk events related to leaked credentials in Azure Active Directory Identity Protection. Here's a simplified breakdown of what it does:
Set Parameters: It defines two parameters: query_frequency (5 minutes) and query_period (2 days).
Filter Risk Events: It retrieves risk events from the AADUserRiskEvents table that were generated within the last 2 days and are specifically from the "IdentityProtection" source with a "leakedCredentials" risk event type.
Summarize Events: For each unique event (Id), it finds the first occurrence time and the most recent occurrence, keeping all details of the latest event.
Filter Recent Events: It only keeps events where the first occurrence was within the last 5 minutes.
Select Columns: It selects specific columns to include in the output, such as user details and risk information.
Generate Alert Link: It creates an alternative alert link for each event using the user ID.
Join with Security Alerts: It performs a left outer join with the SecurityAlert table to find related alerts from Azure Active Directory Identity Protection, matching on the event ID.
Extend Alert Link: It ensures that each event has an alert link, using the alternative link if necessary.
Filter Conditions: It filters out events based on specific conditions:
The result is a list of recent, unresolved user risk events related to leaked credentials, with relevant details and links to further investigate each event.

Jose Sebastián Canós
Released: August 28, 2025
Tables
Keywords
Operators