Entra ID Risk Protection: Leaked Credentials, Risky Users Not Remediated
Entra ID Risk Protection has no trouble finding compromised accounts. The problem is what happens next. Across a large number of tenants the same pattern holds — Entra ID Risk Protection leaked credentials risky users not remediated for weeks or months — because the detection fires, lands in a report, and stays there. This article is about that gap: not the detection engineering, which Microsoft already does for you, but the response workflow that almost nobody operationalizes.
Every risky user in Entra ID carries a risk state. Microsoft Graph documents the possible values as none, confirmedSafe, remediated, dismissed, atRisk, and confirmedCompromised (plus the unknownFutureValue sentinel). Only three of them close a flagged account out of the queue — remediated, dismissed, and confirmedSafe, matching the manual actions Microsoft exposes: dismiss, confirm safe, confirm compromise. Both atRisk and confirmedCompromised leave the user sitting in the risky users report. atRisk means the account is still flagged and nothing has been done to it. confirmedCompromised is the one that catches people out: an administrator looked at the account, agreed it was compromised, and the state alone still does not mean anyone secured it.
Confirming compromise is a labeling action, not a containment action. So is dismissal.
⚠️ Warning: Microsoft states plainly that dismissing risk "doesn't change the user's existing password, it doesn't bring their identity back into a safe state." Dismissal empties the report. It does not fix the account.
The backlog does not expire on its own either. Low-level risk detections and users "persist in the product for six months, after which they're automatically aged out" — but medium and high risk levels persist until remediated or dismissed. A high-risk leaked-credential detection raised two years ago is still in the risky users report today unless a human or a policy closed it.
How the Leaked Credentials Detection Works
Leaked credentials is one of the few risk detections that carries no ambiguity at all.
| Property | Value |
|---|---|
riskEventType | leakedCredentials |
| Risk type | User risk |
| Detection type | Offline |
| Risk level | Always High |
| License | Microsoft Entra ID Free or P1 |
| Hybrid prerequisite | Password hash synchronization (PHS) for on-premises passwords |
Microsoft describes the pipeline behind it: a large-scale credential scanning service that continuously monitors dark web forums, breach dump repositories, paste sites, law enforcement seizure data, and other sources through the Microsoft Threat Intelligence Center (MSTIC), the Microsoft Digital Crimes Unit (DCU), and industry partners. When credentials are discovered, the service validates the actual credential material against the tenant's current valid password hashes, and a detection is emitted only when a confirmed match is found. In Microsoft's own words, the detection "is always as high risk because it represents verified credential exposure, not a heuristic signal."
Two operational consequences follow.
First, this is not a probability score. Atypical travel might be a user on holiday. A leaked-credential detection means a password that currently works in your tenant is in someone else's hands. It deserves an incident, not a triage queue.
Second, you learn late. Leaked credentials is calculated offline, and Microsoft documents that "detections triggered in real-time take 5-10 minutes to surface details in the reports. Offline detections take up to 48 hours to surface in the reports." The window between exposure and your first chance to act is measured in days, which is precisely why the response has to be fast once the signal does arrive.
Password hash synchronization matters here more than most teams realize. A cloud-based password reset through Microsoft Entra remediates the user risk for this detection for both cloud and on-premises passwords — but only "as long as password hash synchronization (PHS) is enabled for on-premises passwords."
💡 Tip: There is a structural trap in the licensing. The leaked credentials detection itself is available on Microsoft Entra ID Free and P1, but risk-based Conditional Access policies and the riskyUsers Microsoft Graph API both require Microsoft Entra ID P2 (or Microsoft Entra Suite). A P1 tenant is told it has confirmed compromised passwords and has no supported way to automate a response to them. The capability split is broken down in Azure AD Premium P2 Features: PIM, Identity Protection, and Access Reviews Nobody Turned On.
Why the Risky User Backlog Never Drains
The tenants with the worst backlogs are rarely the ones that ignored the product. They are the ones where several small gaps compound.
The alerts reach nobody. The "Users at risk detected" email defaults to a High user risk threshold. By default, users actively assigned the Global Administrator, Security Administrator, or Security Reader roles are added to the recipient list, and they must have an Email or Alternate email configured. Two documented caveats break this quietly: a user who elevates into one of those roles through Privileged Identity Management "only receive[s] emails if they're elevated at the time the email is sent," and "sending emails to users in group-assigned roles is not supported." A tenant that grants Security Reader through a group and elevates admins on demand through PIM can receive exactly zero notifications while its dashboard fills up.
Policy thresholds are set above most of the queue. Microsoft's recommended configuration is a user risk policy at High and a sign-in risk policy at Medium and High. That is sound guidance, but it means every medium user-risk and low-risk detection is left for a human, and mediums persist until someone closes them.
Self-remediation is not actually available. Microsoft warns that "users must register for Microsoft Entra multifactor authentication before they face a situation requiring remediation. For hybrid users that are synced from on-premises, password writeback must be enabled. Users not registered are blocked and require administrator intervention." Hybrid users also need PHS plus the opt-in Allow on-premises password change to reset user risk setting before an on-premises password change clears their risk. Where those prerequisites are missing, the policy does not drain the queue — it converts risky users into blocked users and pushes work onto the help desk.
Some detections stopped auto-remediating. Microsoft no longer auto-remediates sessions carrying MFA claims when a token-theft-related detection or the Verified threat actor IP detection fires. The affected detections are Microsoft Entra threat intelligence, Anomalous token, Attacker in the Middle, Verified threat actor IP, and Token issuer anomaly. When one of these hits a user, clearing the risk requires a secure password change and reauthentication with MFA. If your mental model is still "MFA clears everything," these accumulate.
Deleted users are stuck forever. "If a user was deleted from the directory that had a risk present, that user still appears in the risk report even though the account was deleted. Administrators can't dismiss risk for users who were deleted from the directory." Clearing them requires a Microsoft support case. Every offboarded risky user permanently inflates the count, which trains the team to stop trusting the number.
The legacy automation has an expiry date. Microsoft's guidance is explicit: "The legacy risk policies configured in Microsoft Entra ID Protection will be retired on October 1, 2026." Tenants whose only automated response is a legacy ID Protection risk policy — rather than a Conditional Access policy — will lose it, and a backlog that was being drained automatically will start growing again.
Detection: Measure Your Own Remediation Backlog
The portal reports tell you who is risky. They do not tell you how long people stay risky, which is the number that matters. For that you need the risk data in Log Analytics.
Configure diagnostic settings in Entra ID > Monitoring & health > Diagnostic settings and export the RiskyUsers and UserRiskEvents categories (Microsoft also exposes RiskyServicePrincipals, ServicePrincipalRiskEvents, RiskyAgents, and AgentRiskEvents). They land in the AADRiskyUsers and AADUserRiskEvents tables.
ℹ️ Note: "Log Analytics only has visibility into data as it is streamed. Events prior to enabling the sending of events from Microsoft Entra ID don't appear." Turn the export on before you need the history — risky sign-ins are retained for only 7 days on Free and 30 days on P1 and P2.
What to watch
| Signal | Table | What it tells you |
|---|---|---|
RiskState == "atRisk" at high RiskLevel | AADRiskyUsers | Accounts flagged and never closed |
RiskEventType == "leakedCredentials" | AADUserRiskEvents | Confirmed credential exposure, always high risk |
RiskDetail == "adminDismissedAllRiskForUser" | AADRiskyUsers | Risk closed by a click — password unchanged |
RiskDetail == "adminConfirmedUserCompromised" | AADRiskyUsers | Compromise acknowledged; verify containment followed |
RiskState == "confirmedCompromised" still recent | AADRiskyUsers | Accounts labeled compromised and still live |
DetectionTimingType == "offline" | AADUserRiskEvents | Detections that landed after the sign-in completed |
Open leaked-credential detections
AADUserRiskEvents
| where TimeGenerated > ago(90d)
| where RiskEventType == "leakedCredentials"
| where RiskState == "atRisk"
| project DetectedDateTime, UserPrincipalName, RiskLevel, RiskState, RiskDetail, DetectionTimingType
| order by DetectedDateTime asc
Every row is an account whose password is known to be exposed and which nobody has touched. Sorted oldest first, the top of this list is your worst exposure.
How old is the at-risk backlog
AADRiskyUsers
| summarize arg_max(TimeGenerated, RiskState, RiskLevel, RiskDetail, RiskLastUpdatedDateTime)
by UserPrincipalName
| where RiskState == "atRisk"
| where RiskLevel in ("high", "medium")
| extend DaysAtRisk = datetime_diff('day', now(), RiskLastUpdatedDateTime)
| project UserPrincipalName, RiskLevel, RiskDetail, RiskLastUpdatedDateTime, DaysAtRisk
| order by DaysAtRisk desc
AADRiskyUsers receives a record each time a user's risky state changes, so arg_max collapses the stream to the latest known state per user before the age is calculated.
Audit the dismiss button
AADRiskyUsers
| where TimeGenerated > ago(90d)
| where RiskState == "dismissed" and RiskDetail == "adminDismissedAllRiskForUser"
| project TimeGenerated, UserPrincipalName, RiskLevel, RiskDetail
| order by TimeGenerated desc
Dismissal is a legitimate outcome after investigation. It is also the fastest way to make a dashboard look healthy. Cross-check this list against your ticketing system: a dismissal with no matching investigation record is a decision nobody can defend later.
Time to close, by detection type
AADUserRiskEvents
| where TimeGenerated > ago(90d)
| where RiskLevel == "high"
| where RiskState in ("remediated", "dismissed", "confirmedCompromised")
| extend HoursToClose = datetime_diff('hour', LastUpdatedDateTime, DetectedDateTime)
| summarize Detections = count(),
MedianHours = percentile(HoursToClose, 50),
P90Hours = percentile(HoursToClose, 90)
by RiskEventType
| order by Detections desc
This is the metric to put in front of leadership. "We have 40 risky users" invites a shrug; "our median time to close a confirmed leaked credential is 26 days" does not.
Querying the same data from Microsoft Graph
The riskyUsers API requires a Microsoft Entra ID P2 (or Microsoft Entra Suite) license. Reading it needs the IdentityRiskyUser.Read.All permission, and for delegated access the signed-in user must hold Global Reader, Security Operator, Security Reader, or Security Administrator.
GET https://graph.microsoft.com/v1.0/identityProtection/riskyUsers?$filter=riskState eq 'atRisk' and riskLevel eq 'high'
The endpoint supports $filter and $select, with a maximum page size of 500 objects via $top. The same query through the Graph PowerShell SDK:
Import-Module Microsoft.Graph.Identity.SignIns
Get-MgRiskyUser -Filter "riskState eq 'atRisk' and riskLevel eq 'high'" -All |
Select-Object UserPrincipalName, RiskLevel, RiskState, RiskDetail, RiskLastUpdatedDateTime
Run it on a schedule and alert on the count, not on individual events. A backlog that grows week over week is the finding.
Remediation: Drain the Queue and Keep It Drained
💡 Quick Win: Filter the risky users report on Risk state = At risk and Risk level = High, then sort oldest first. Everything above your incident-response SLA is an open incident nobody opened.
1. Know what each action actually does
Before automating anything, make sure the team agrees on what each button means. Microsoft documents the resulting state and detail for every path:
| Action | Resulting risk state | Risk detail | Secures the account? |
|---|---|---|---|
| User passes MFA (sign-in risk policy) | Remediated | User passed multifactor authentication | Sign-in risk only |
| User completes secure password change (user risk policy) | Remediated | User performed secured password reset | Yes |
| Admin requires a password change | Remediated | User performed secure password change | Yes |
| Admin generates a temporary password | Remediated | Admin generated temporary password for user | Yes |
| Admin dismisses the risk | Dismissed | Admin dismissed all risk for user | No |
| Admin confirms compromised | Confirmed compromised | Admin confirmed user compromised | No — containment is a separate step |
| System reassessment | Dismissed | Microsoft Entra ID Protection assessed sign-in safe | Automatic, no action needed |
The naming is genuinely confusing and Microsoft flags it: the risk detail "User performed secured password reset" is a system-reported label that indicates the user completed a secure password change (MFA followed by a password change), not a self-service password reset flow.
Note also the role split — Security Operator is the least privileged role to dismiss user risk, while User Administrator is required to reset passwords. Resetting a password from within ID Protection needs both.
2. Work the leaked-credential backlog once, by hand
Microsoft's investigation steps for this detection are specific, and they are the right runbook for clearing the existing queue:
- Assess the scope of exposure — review the user's risk history and sign-in logs for correlated sign-in risk (unfamiliar locations, anonymous IP addresses, atypical travel).
- Check whether the password already changed after the leak was detected; if it did, the risk may already be self-remediated.
- Block access if an attacker is active — block the user, reset the password, and revoke all refresh tokens where the logs show unauthorized access.
- Review for lateral movement — privilege escalation, new app registrations, mailbox rule changes, access to sensitive resources.
- Verify connected accounts — if the user reuses passwords, treat the credential as compromised beyond your tenant.
3. Make "confirm compromised" trigger containment
Confirming compromise sets the risk level to high and feeds Microsoft's models, but Microsoft lists the containment actions separately: request a password change, block the user if the attacker can reset the password or perform MFA, revoke refresh tokens, disable any devices considered compromised, and revoke all access tokens if you use continuous access evaluation.
Automate the labeling so the human time goes to the containment:
POST https://graph.microsoft.com/v1.0/identityProtection/riskyUsers/confirmCompromised
Content-Type: application/json
{
"userIds": [
"29f270bb-4d23-4f68-8a57-dc73dc0d4caf",
"20f91ec9-d140-4d90-9cd9-f618587a1471"
]
}
This action requires IdentityRiskyUser.ReadWrite.All, with Security Administrator as the least privileged supported role, and returns 204 No Content on success.
4. Automate the steady state with Conditional Access
Manual drainage does not scale. Two risk-based Conditional Access policies keep the queue near zero, and Microsoft is explicit that they must be separate — "don't combine sign-in risk and user risk conditions in the same Conditional Access policy."
- User risk policy: select Require risk remediation when user risk is High. Choosing it automatically applies Require authentication strength as a grant control and Sign-in frequency – Every time as a session control.
- Sign-in risk policy: require multifactor authentication when sign-in risk is Medium or High, with sign-in frequency set to every time.
Exclude emergency access accounts and service principals, start in report-only mode, and confirm the impact before switching to On. The full configuration walkthrough is in Azure Identity Protection: Blocking Leaked Credentials — and report-only is a rollout stage, not a destination, which is a trap covered in Conditional Access Report-Only Mode, Stale Exclusions. Get the exclusion list right first, using the guidance in Entra ID Break Glass Emergency Access Accounts, and check the policy set as a whole against Entra ID Conditional Access Gaps.
5. Fix the prerequisites that block self-remediation
- Confirm users are registered for MFA before the policy goes live; unregistered users get blocked instead of remediated. Registration coverage is only half the story — see Azure Identity Security: Why MFA Alone Is Not Enough.
- For hybrid identities, enable password hash synchronization and turn on Allow on-premises password change to reset user risk under Protection > Identity Protection > Settings. Microsoft notes this is opt-in only and recommends securing the on-premises password change process — for example by requiring MFA before an on-premises change.
6. Route the notifications to someone who reads them
Verify that recipients of the Users at risk detected alert have a valid Email or Alternate email, do not depend on group-assigned roles, and account for PIM elevation timing. Consider lowering the alert threshold below the default High if your team has the capacity, and switch on the weekly digest for trend visibility.
7. Migrate off the legacy risk policies
If risk enforcement still lives in the legacy ID Protection policies rather than Conditional Access, migrate before October 1, 2026: build the equivalent Conditional Access policies in report-only mode, validate them, enable them, then disable the old policies under ID Protection > Dashboard.
How EtcSec Detects This
EtcSec audits the response path, not just the detection layer.
The Risk Protection checks flag RISK_LEAKED_CREDENTIALS (Leaked Credentials Not Blocked) when accounts with confirmed compromised credentials are still active and unblocked, and RISK_USERS_NOT_REMEDIATED (Risky Users Not Remediated) when accounts flagged as risky were never remediated or dismissed. Both are rated Critical, because both describe an account an attacker can currently use.
Alongside them, RISK_HIGH_RISK_USERS_ACTIVE surfaces high-risk users whose accounts remain enabled, RISK_SIGNINS_NOT_INVESTIGATED catches risky sign-ins with no follow-up, and RISK_NO_AUTOMATED_RESPONSE identifies tenants where risk is visible but no automated containment exists.
For the broader tenant review these checks sit inside, see How to Audit Microsoft Entra ID Security. For the sign-in-side detections that feed user risk, see Entra ID AiTM Token Replay, Impossible Travel Detection, and MFA Push Fatigue and Password Spraying: Detection and Prevention.
ℹ️ Note: EtcSec automatically checks for these vulnerabilities during every AD/Azure audit. Run a free audit to verify your environment.
Primary References
- What are risk detections? — Microsoft Entra ID Protection
- Risk detection types and levels
- Remediate risks and unblock users
- Investigate risk with Microsoft Entra ID Protection
- Risk policies — Microsoft Entra ID Protection
- Configure Microsoft Entra ID Protection notifications
- Export and use Microsoft Entra ID Protection data
- What is Microsoft Entra ID Protection?
- riskyUser resource type — Microsoft Graph v1.0
- riskyUser: confirmCompromised — Microsoft Graph v1.0
- List riskyUsers — Microsoft Graph v1.0
- Azure Monitor Logs reference — AADRiskyUsers
- Azure Monitor Logs reference — AADUserRiskEvents
Explore the identity security pages that support this topic

