๐ก๏ธ Recipe ยท Security & Compliance
Review Risky Sign-Ins for Impossible Travel, Unfamiliar Locations, and Repeated Failures
Audit weekend and off-hours sign-in activity in Microsoft Entra ID to surface compromise indicators and triage suspicious accounts
Complexity
Intermediate
Impact
security + identity-protection + audit + incident-response + entra-id
Context
Why This Matters
Why this matters
Attackers frequently target accounts during off-hours โ weekends, holidays, and overnight windows โ when IT staff are less likely to respond quickly. Microsoft Entra ID Identity Protection and the sign-in audit logs together give you a detailed picture of every authentication attempt: where it came from, what device was used, whether it succeeded, and whether Microsoft's risk engine scored it as anomalous.
A periodic review of risky sign-ins lets you catch three high-value patterns:
- Impossible travel โ the same account authenticating from two geographically distant locations in a short time window, which usually indicates credential theft.
- Unfamiliar locations โ sign-ins from countries or networks the user has never used before, often the first visible sign of a compromised password.
- Repeated failures โ bursts of failed attempts that may indicate password spraying, brute force, or MFA fatigue attacks.
When to run it
- Every Monday morning to cover the prior weekend.
- The morning after any extended holiday.
- Ad-hoc when a user, manager, or helpdesk reports a suspicious email, device prompt, or login alert.
- As part of quarterly security reviews for privileged accounts.
Expected Outcomes
What you'll have when you finish
- A complete inventory of risky sign-ins and risk detections for the selected time window.
- A per-user breakdown of failures, locations, IP addresses, and devices used.
- A clear verdict for each flagged user โ low/medium/high risk, with the reasoning documented.
- Remediation actions taken (revoked sessions, disabled accounts, forced password resets) where warranted.
- A record suitable for compliance and audit trails (SOC 2, ISO 27001, HIPAA incident logs).
Risks & Considerations
Cautions
- Don't disable accounts reflexively. Multiple cities within a single country or 5โ10 IPs over a weekend are usually ISP/mobile carrier routing, not compromise. Investigate before containing.
- Error code 65001 is not a credential attack. It means admin consent has not been granted for an application. Don't treat it as a brute-force indicator.
- Aggregated location data can mislead. If a tool groups sign-ins by "all locations seen," a user who signed in from Israel last month and Las Vegas this weekend may look like impossible travel. Always drill into the chronological timeline before concluding.
- Privileged accounts deserve extra scrutiny. Any anomaly on a Global Admin, Privileged Role Admin, or Exchange Admin account should be treated as high severity even if the evidence is thin.
- Preserve evidence before remediating. Export the sign-in log rows and risk detections to immutable storage before revoking sessions or resetting passwords โ you may need them for a formal investigation.
- Identity Protection requires Entra ID P2 (or Microsoft 365 E5). Without it, the
riskyUsersandriskDetectionsendpoints return limited or no data and you must rely on the raw sign-in logs.
Required Permissions
| Permission | Why It's Needed |
|---|---|
| AuditLog.Read.All | Read the Entra ID sign-in audit logs to retrieve success and failure events, locations, IPs, and device details. |
| IdentityRiskyUser.Read.All | Query currently risky users and their risk state (atRisk, confirmedCompromised, remediated). |
| IdentityRiskEvent.Read.All | Read Identity Protection risk detections (impossible travel, unfamiliar sign-in, leaked credentials, etc.). |
| User.ReadWrite.All | Required if you act on findings โ disable accounts or update user properties. |
| Directory.Read.All | Resolve user IDs to UPNs and display names, and read directory role memberships for privileged-account context. |
| User.RevokeSessions.All | Revoke active refresh tokens for compromised or suspicious accounts via /revokeSignInSessions. |
The fastest way to get this done: just ask Dex. Copy the prompt below and paste it into your Dex conversation.
For IT Admins
Paste into Dex Pro
Review risky sign-ins via the Microsoft Entra admin center
Step 1 โ Open Identity Protection
- Navigate to .
- On the overview page, note the totals for Risky users, Risky sign-ins, and Risk detections.
Step 2 โ Review risky sign-ins
- Open .
- Set the Date filter to cover the window you want to audit (e.g., the last weekend, or "Last 7 days").
- Optionally filter by Risk level (High/Medium/Low) and Risk state (At risk / Confirmed compromised).
- Click each sign-in to inspect the Basic info, Location, Device info, and Risk info tabs. Pay particular attention to the Risk event types column โ values like
unfamiliarFeatures,atypicalTravel, ormaliciousIPAddressare the highest-signal indicators.
Step 3 โ Review risk detections
- Open .
- Same date range. This view shows why a sign-in was risky, even when it was allowed through.
- Sort by Risk level descending and walk through any High/Medium entries.
Step 4 โ Cross-check against sign-in logs
- Navigate to .
- Apply filter:
Status = Failureand your target date range. - Group by user (use the User column filter) and look for users with 5+ failures or failures spanning 2+ countries within a few hours.
- Open any suspicious row to see the Authentication Details, Conditional Access, and Additional Details tabs.
Step 5 โ Triage each flagged user
- For each user who appears suspicious, build a quick timeline: sort their sign-ins by Date ascending and look for city/country changes within an unrealistically short interval.
- Check the IP address and Autonomous system fields โ residential IPs from the user's home country are usually benign; hosting-provider or VPN ASNs on a historically on-site user are worth investigating.
- Confirm the failure reason codes.
50126= bad password,50053= account locked,50055= password expired,530003= device not compliant,65001= app consent missing (not a credential attack).
Step 6 โ Take action
- For confirmed compromise: open the user's profile, select Revoke sessions, then Reset password, and mark the user Confirm compromised in Identity Protection.
- For suspicious but unconfirmed: contact the user out-of-band (phone, not email), verify their activity, and mark the user Confirm safe or Dismiss user risk once cleared.
- Document the review in your ticketing or SIEM system with the evidence (risk detection IDs, sign-in correlation IDs).
Microsoft Graph API recipe
Base URL: https://graph.microsoft.com/v1.0. All calls require a bearer token with the permissions listed above.
1. List risk detections in a time window
GET /identityProtection/riskDetections?$filter=activityDateTime ge 2026-02-14T00:00:00Z and activityDateTime le 2026-02-15T23:59:59Z&$orderby=activityDateTime desc&$top=200Returns risk events such as unfamiliarFeatures, anonymizedIPAddress, maliciousIPAddress, atypicalTravel, leakedCredentials, with user, location, IP, and risk level.
2. List currently risky users
GET /identityProtection/riskyUsers?$filter=riskState eq 'atRisk' or riskState eq 'confirmedCompromised'3. Pull all sign-ins for the window (success and failure)
GET /auditLogs/signIns?$filter=createdDateTime ge 2026-02-14T00:00:00Z and createdDateTime le 2026-02-15T23:59:59Z&$orderby=createdDateTime desc&$top=500Follow @odata.nextLink for pagination. Select fields you need to reduce payload: &$select=id,createdDateTime,userPrincipalName,userId,ipAddress,location,status,riskLevelDuringSignIn,riskEventTypes,deviceDetail,appDisplayName.
4. Drill into one user's timeline
GET /auditLogs/signIns?$filter=userId eq '{userId}' and createdDateTime ge {start} and createdDateTime le {end}&$orderby=createdDateTime asc5. Remediation calls
# Revoke all active refresh tokens
POST /users/{userId}/revokeSignInSessions
# Disable the account
PATCH /users/{userId}
Content-Type: application/json
{ "accountEnabled": false }
# Mark user as compromised in Identity Protection
POST /identityProtection/riskyUsers/confirmCompromised
Content-Type: application/json
{ "userIds": ["{userId}"] }Triage logic
Client-side, join the three datasets by userId and compute per-user metrics: total attempts, failure count, distinct countries, distinct IPs, distinct ASNs, and whether any sign-in had riskLevelDuringSignIn of medium or high. Flag a user as suspicious when failures โฅ 3, OR distinct countries โฅ 2 within 8 hours, OR any medium/high risk sign-in is present.
PowerShell recipe using Microsoft.Graph
The script below authenticates with the required scopes, pulls risk detections, risky users, and raw sign-in logs for a date range, then builds a per-user summary and prints suspicious accounts.
Prerequisites
- PowerShell 7+ recommended.
Install-Module Microsoft.Graph -Scope CurrentUser.- Run with an account that has at least the Security Reader directory role (read-only review) or Security Administrator (for remediation).
How it works
- Connects with
Connect-MgGraphrequesting the read scopes plus optional write scopes if-EnableRemediationis set. - Resolves the date range (defaults to the most recent weekend).
- Calls
Get-MgRiskDetection,Get-MgRiskyUser, andGet-MgAuditLogSignIn. - Groups the sign-ins by user and computes failures, countries, IPs, and a risk score.
- Prints a color-coded summary. If
-EnableRemediationis passed, prompts the admin to revoke sessions for each flagged user.
Interpreting the output
- Risk score 6+ โ investigate immediately.
- Risk score 3โ5 โ review and contact the user to confirm.
- Risk score 1โ2 โ likely benign (mobile carrier, ISP rotation) but worth noting.
Always correlate country/IP changes against the user's declared travel or out-of-office status before taking action.
Next steps