Detection rules › Kusto

Tailscale: Mass credential revocation in short window

Status
available
Severity
high
Time window
1h
Group by
ActorLogin
Source
github.com/Azure/Azure-Sentinel

Identifies when five or more API keys, OAuth clients, or auth keys are revoked or deleted within one hour. May be routine rotation, or a typical cleanup pattern after credential compromise.

MITRE ATT&CK coverage

TacticTechniques
Stealth

Rule body

id: f817e2fa-6fa0-fc25-5369-cef9b58771af
name: "Tailscale: Mass credential revocation in short window"
description: |
  Identifies when five or more API keys, OAuth clients, or auth keys are revoked or deleted within one hour. May be routine rotation, or a typical cleanup pattern after credential compromise.
severity: High
status: Available
requiredDataConnectors:
  - connectorId: TailscaleCCF
    dataTypes:
      - Tailscale_Audit_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - DefenseEvasion
  - Impact
relevantTechniques:
  - T1070
query: |
  Tailscale_Audit_CL
        | where Action in ("REVOKE", "DELETE")
        | where tostring(Target.type) in ("API_KEY", "OAUTH_CLIENT", "AUTH_KEY")
        | extend ActorLogin = tostring(Actor.loginName)
        | summarize
            RevokedCount = count(),
            TargetTypes = make_set(tostring(Target.type)),
            TargetIds = make_set(tostring(Target.id)),
            FirstEvent = min(TimeGenerated),
            LastEvent = max(TimeGenerated)
          by ActorLogin, bin(TimeGenerated, 1h)
        | where RevokedCount >= 5
        | project TimeGenerated = LastEvent, ActorLogin, RevokedCount, TargetTypes, TargetIds, FirstEvent, LastEvent
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: ActorLogin
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: PT5H
    matchingMethod: AllEntities
kind: Scheduled
version: 1.0.0

Stages and Predicates

Stage 1: source

Tailscale_Audit_CL

Stage 2: where

| where Action in ("REVOKE", "DELETE")

Stage 3: where

| where tostring(Target.type) in ("API_KEY", "OAUTH_CLIENT", "AUTH_KEY")

Stage 4: extend

| extend ActorLogin = tostring(Actor.loginName)

Stage 5: summarize

| summarize
          RevokedCount = count(),
          TargetTypes = make_set(tostring(Target.type)),
          TargetIds = make_set(tostring(Target.id)),
          FirstEvent = min(TimeGenerated),
          LastEvent = max(TimeGenerated)
        by ActorLogin, bin(TimeGenerated, 1h)

Stage 6: where

| where RevokedCount >= 5

Stage 7: project

| project TimeGenerated = LastEvent, ActorLogin, RevokedCount, TargetTypes, TargetIds, FirstEvent, LastEvent

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
Actionin
  • DELETE
  • REVOKE
field:"Action" kind:in
RevokedCountge
  • 5
field:"RevokedCount" kind:ge value:"5"
typein
  • API_KEY transforms: tostring
  • AUTH_KEY transforms: tostring
  • OAUTH_CLIENT transforms: tostring
field:"type" kind:in

Output fields

These fields are emitted when the rule matches.

FieldSource
ActorLoginproject
FirstEventproject
LastEventproject
RevokedCountproject
TargetIdsproject
TargetTypesproject
TimeGeneratedproject