Query Details

10 Stale Token After Password Change

Query

id: d5e1f3a4-b9c0-2d6e-7f8a-9b0c1d2e3f4a
name: Stale Token Used After Password Change or Auth Method Update
description: |
  Community rule by David Alonso (https://github.com/davidalonsod/Dalonso-Security-Repo). Licensed under The Unlicense.

  Detects when a user's password or authentication methods were changed/reset in Azure AD
  Audit Logs, but non-interactive token refreshes continue to occur AFTER the change.
  This is a strong indicator that an attacker has a pre-existing refresh token that
  survived the password change — a key tactic to maintain persistent access even after
  the victim or IT team reset the compromised credentials.
  MITRE ATT&CK: T1528 (Steal Application Access Token), T1078 (Valid Accounts)
severity: High
requiredDataConnectors:
- connectorId: AzureActiveDirectory
  dataTypes:
  - AADNonInteractiveUserSignInLogs
  - AuditLogs
queryFrequency: PT1H
queryPeriod: PT24H
triggerOperator: gt
triggerThreshold: 0
enabled: true
tactics:
- Persistence
- CredentialAccess
- DefenseEvasion
relevantTechniques:
- T1078
- T1528
- T1550
query: |
  let PasswordChanges =
      AuditLogs
      | where TimeGenerated > ago(24h)
      | where OperationName has_any (
          "Reset password",
          "Change password",
          "User changed password",
          "Admin updated user authentication method",
          "Update Authentication Method",
          "Delete Authentication Method"
        )
      | extend UPN = tostring(TargetResources[0].userPrincipalName)
      | where isnotempty(UPN)
      | summarize ChangeTime = max(TimeGenerated) by UPN;
  AADNonInteractiveUserSignInLogs
  | where TimeGenerated > ago(24h)
  | where ResultType == 0
  | join kind=inner PasswordChanges on $left.UserPrincipalName == $right.UPN
  | where TimeGenerated > ChangeTime
  | summarize
      TokensAfterChange = count(),
      IPs               = make_set(IPAddress),
      Countries         = make_set(Location),
      Apps              = make_set(AppDisplayName),
      LastSeen          = max(TimeGenerated),
      FirstTokenAfter   = min(TimeGenerated)
    by UserPrincipalName, ChangeTime
  | extend IPAddress = tostring(IPs[0])
  | order by TokensAfterChange desc
entityMappings:
- entityType: Account
  fieldMappings:
  - identifier: FullName
    columnName: UserPrincipalName
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: IPAddress
alertDetailsOverride:
  alertDisplayNameFormat: 'Stale Token Active After Credential Change - {{UserPrincipalName}}'
  alertDescriptionFormat: 'User {{UserPrincipalName}} had credentials changed, but {{TokensAfterChange}} non-interactive token refreshes were observed afterward. Possible stale refresh token bypassing the
    credential reset.'
customDetails:
  TokensAfterChange: TokensAfterChange
  Countries: Countries
  Apps: Apps
  PasswordChangeTime: ChangeTime
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: PT5H
    matchingMethod: AnyAlert
    groupByEntities:
    - Account
    groupByAlertDetails: []
    groupByCustomDetails: []
version: 1.0.0
kind: Scheduled
tags:
- Community
- David Alonso
- Threat Hunting

Explanation

This query is designed to detect potential security threats in Azure Active Directory (Azure AD) by identifying instances where a user's password or authentication method has been changed, but non-interactive token refreshes continue to occur afterward. This situation suggests that an attacker might have a refresh token that remains valid even after the password change, allowing them to maintain access.

Here's a simplified breakdown of the query:

  1. Purpose: To identify if an attacker is using a stale refresh token to access an account after the user's credentials have been updated.

  2. Data Sources: It uses data from Azure AD's Audit Logs and Non-Interactive User Sign-In Logs.

  3. Process:

    • It first checks for any password or authentication method changes within the last 24 hours.
    • It then looks for non-interactive sign-ins (token refreshes) that occur after these changes.
    • If such sign-ins are found, it indicates that a refresh token is being used despite the credential update.
  4. Severity: The alert is marked as high severity because it suggests a potential security breach.

  5. MITRE ATT&CK Techniques: It relates to techniques T1528 (Steal Application Access Token) and T1078 (Valid Accounts).

  6. Alert Details: If such activity is detected, an alert is generated with details about the user, the number of token refreshes, IP addresses, countries, and applications involved.

  7. Incident Management: The query is set to create an incident if such activity is detected, allowing for further investigation and response.

Overall, this query helps in threat hunting by identifying suspicious activity that could indicate an attacker is bypassing security measures to maintain unauthorized access to an account.

Details

David Alonso profile picture

David Alonso

Released: June 12, 2026

Tables

AADNonInteractiveUserSignInLogsAuditLogs

Keywords

AzureActiveDirectoryAuditLogsAADNonInteractiveUserSignInLogsUserAccountIPAddressLocationAppDisplayNameTokenPasswordAuthenticationMethod

Operators

lethas_anytostringisnotemptysummarizeagowherejoinonextendcountmake_setmaxminorder bydesc

Actions