The Account Was Disabled — But the Refresh Token Still Worked
The incident response looked complete.
The compromised user account had been identified. The password had been reset. The account had been disabled.
Everyone expected the activity to stop.
It didn't.
Agent Foskett had one question: if the attacker could no longer authenticate as the user, what exactly was still keeping the session alive?

The Session Question
Disabling an identity and terminating every session associated with it are related containment actions — but they are not the same investigation question.
The account was disabled at 9:17 AM
First establish the last successful sign-ins
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
let User = "alex@contoso.com";
let DisableTime = datetime(2026-08-25 09:17:00);
SigninLogs
| where TimeGenerated between (DisableTime - 12h .. DisableTime + 2h)
| where UserPrincipalName =~ User
| where ResultType == 0
| project TimeGenerated,
UserPrincipalName,
IPAddress,
AppDisplayName,
ClientAppUsed,
ConditionalAccessStatus,
DeviceDetail,
CorrelationId
| order by TimeGenerated ascNow separate interactive from non-interactive activity
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
let User = "alex@contoso.com";
let DisableTime = datetime(2026-08-25 09:17:00);
AADNonInteractiveUserSignInLogs
| where TimeGenerated between (DisableTime .. DisableTime + 6h)
| where UserPrincipalName =~ User
| project TimeGenerated,
UserPrincipalName,
IPAddress,
AppDisplayName,
ResourceDisplayName,
ResultType,
ResultDescription,
ConditionalAccessStatus,
DeviceDetail,
CorrelationId
| order by TimeGenerated ascWas the same attacker infrastructure still present?
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
let User = "alex@contoso.com";
let DisableTime = datetime(2026-08-25 09:17:00);
AADNonInteractiveUserSignInLogs
| where TimeGenerated between (DisableTime - 6h .. DisableTime + 6h)
| where UserPrincipalName =~ User
| summarize Events = count(),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated),
Apps = make_set(AppDisplayName, 20),
Results = make_set(ResultType, 10)
by IPAddress
| order by LastSeen desc
