Entra session revocation bypass

Severity criticalCloud & SaaSOrdered sequencestablecloud.identity.entra_session_revocation_bypass · v1.0.0

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

  • T1550.001Use Alternate Authentication Material: Application Access Token· Defense Evasion
  • T1078.004Valid Accounts: Cloud Accounts· Initial Access
  • T1098Account Manipulation· Persistence

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.

Browse all detections