Entra session revocation bypass
An account kept working after its sessions were revoked.
What it detects
An account kept working after its sessions were revoked.
Revocation is the containment step. When an account is believed compromised, an administrator resets the password and invalidates every refresh token — recorded as Update StsRefreshTokenValidFrom Timestamp. — and the expectation is that everything holding a token for that account stops.
It does not always stop. Access tokens already issued remain valid for their lifetime, and a client that re-presents one keeps working until it expires; a token minted through a path the revocation did not cover keeps working longer. Either way the tenant believes the account is contained while the attacker is still inside it, which is worse than not having revoked at all, because the incident is closed.
This is the shape that motivated coalescing group keys. The revocation names the VICTIM in target_user_name — the actor is the administrator — while the victim's own later activity names them in user_name. Grouping applies one field list to every step, so a plain [user_name] buckets the revocation under the admin and the two halves never meet. "target_user_name|user_name" resolves to the victim on both.
MITRE ATT&CK mapping
False positives and triage
The biggest source of noise — a user changing their OWN password and carrying on — is excluded by the rule itself, which requires the actor to differ from the subject. What remains needs two checks.
First, the ACTOR. Directory-synchronisation and password-writeback services revoke sessions as routine plumbing; fim_password_service@*.onmicrosoft.com is the one to expect, and it accounted for half the residual hits on a real tenant export here. Identify those service principals once and allowlist them, in preference to loosening the rule — a scheduled service revoking on a fixed cadence is easy to recognise and easy to exclude, while the count is not what distinguishes it.
Second, the SOURCE of the continued activity. A helpdesk reset while the user is mid-session produces this shape honestly, and the discriminator is what came before the activity: a genuine reset is followed by a fresh interactive sign-in from the user's usual address, whereas this technique shows activity with no sign-in in front of it, often from an address that was already suspicious.
When the revocation WAS incident response, the continued activity is the finding rather than the noise, and the containment needs redoing: revoke again, disable the account, and remove any token-issuing artefact the actor added — an app credential, a device registration, a delegated grant — because a token that outlives a revocation usually came from one.
The rule
Declarative YAML read by the detection engine — data, never executed. Confidence 65%. Source: rules/cloud/entra_session_revocation_bypass.yaml, licensed under the Apache License 2.0.
id: cloud.identity.entra_session_revocation_bypass
version: 1.0.0
status: stable
severity: critical
confidence: 0.65
platforms: [application]
mitre_techniques: [T1550.001, T1078.004, T1098]
description: |
An account kept working after its sessions were revoked.
Revocation is the containment step. When an account is believed compromised, an
administrator resets the password and invalidates every refresh token — recorded
as `Update StsRefreshTokenValidFrom Timestamp.` — and the expectation is that
everything holding a token for that account stops.
It does not always stop. Access tokens already issued remain valid for their
lifetime, and a client that re-presents one keeps working until it expires; a
token minted through a path the revocation did not cover keeps working longer.
Either way the tenant believes the account is contained while the attacker is
still inside it, which is worse than not having revoked at all, because the
incident is closed.
This is the shape that motivated coalescing group keys. The revocation names the
VICTIM in `target_user_name` — the actor is the administrator — while the victim's
own later activity names them in `user_name`. Grouping applies one field list to
every step, so a plain `[user_name]` buckets the revocation under the admin and
the two halves never meet. `"target_user_name|user_name"` resolves to the victim
on both.
sequence:
# An hour. Access tokens are typically good for about that long, so activity
# inside the window is the part revocation was supposed to stop; beyond it, a
# fresh sign-in is the more likely explanation and this rule should not claim it.
within_seconds: 3600
group_by: ["target_user_name|user_name"]
order: strict
steps:
- id: sessions_revoked
match:
provider_any: [Office365, AzureAD]
event_action_contains_any:
- "Update StsRefreshTokenValidFrom Timestamp"
- "Revoke sign-in sessions"
- "RevokeSignInSessions"
- "Reset user password"
# Containment only. Someone changing their OWN password and carrying on
# produces the identical pair of events, and is the overwhelming majority:
# eight of the fourteen revocations in a 9,611-record real tenant export
# were self-service, and without this the rule alerted six times on that
# file at critical severity. Requiring the actor to differ from the subject
# took it to zero there while leaving the technique intact.
user_name_not_eq_field: target_user_name
- id: activity_continued
match:
event_outcome: success
event_action_not_contains_any:
- "Update StsRefreshTokenValidFrom Timestamp"
- "Revoke sign-in sessions"
- "RevokeSignInSessions"
- "Reset user password"
correlation_keys: [user_name, source_ip]
false_positive_guidance: |
The biggest source of noise — a user changing their OWN password and carrying on —
is excluded by the rule itself, which requires the actor to differ from the
subject. What remains needs two checks.
First, the ACTOR. Directory-synchronisation and password-writeback services revoke
sessions as routine plumbing; `fim_password_service@*.onmicrosoft.com` is the one
to expect, and it accounted for half the residual hits on a real tenant export
here. Identify those service principals once and allowlist them, in preference to
loosening the rule — a scheduled service revoking on a fixed cadence is easy to
recognise and easy to exclude, while the count is not what distinguishes it.
Second, the SOURCE of the continued activity. A helpdesk reset while the user is
mid-session produces this shape honestly, and the discriminator is what came
before the activity: a genuine reset is followed by a fresh interactive sign-in
from the user's usual address, whereas this technique shows activity with no
sign-in in front of it, often from an address that was already suspicious.
When the revocation WAS incident response, the continued activity is the finding
rather than the noise, and the containment needs redoing: revoke again, disable
the account, and remove any token-issuing artefact the actor added — an app
credential, a device registration, a delegated grant — because a token that
outlives a revocation usually came from one.
Related detections
Run this rule on your own logs — offline
KIROSEC runs this rule and the rest of the library over Windows, Linux, macOS and cloud audit logs on the analyst's own machine. Every alert links to the events that raised it, and nothing leaves the device.
