Azure Key Vault Multi-Vault Secret Retrieval Burst by Application

Identifies a burst of successful Azure Key Vault secret retrievals by the same principal and application across multiple vaults. Adversaries with compromised application credentials may collect stored secrets at scale to access additional services or move laterally.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2026/11/03"
  3integration = ["azure"]
  4maturity = "production"
  5updated_date = "2026/11/04"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10Identifies a burst of successful Azure Key Vault secret retrievals by the same principal and application across
 11multiple vaults. Adversaries with compromised application credentials may collect stored secrets at scale to access
 12additional services or move laterally.
 13"""
 14false_positives = [
 15    """
 16    Authorized inventory jobs, secret migration tools, and multi-vault deployment pipelines may retrieve many secrets
 17    across several vaults within 15 minutes.
 18    """,
 19]
 20from = "now-30m"
 21interval = "5m"
 22language = "esql"
 23license = "Elastic License v2"
 24name = "Azure Key Vault Multi-Vault Secret Retrieval Burst by Application"
 25note = """## Triage and analysis
 26
 27### Investigating Azure Key Vault Multi-Vault Secret Retrieval Burst by Application
 28
 29Azure Key Vault stores credentials that applications use to access other services. A compromised identity can use its existing vault permissions to collect these credentials and extend access to additional resources. This rule matches the Storm-0940 hunting pattern: at least 20 successful SecretGet requests by one principal and application across at least three vaults in a 15-minute window. Single-vault application startup and refresh traffic is outside this threshold. Repeated reads of the same secret still count toward the volume.
 30
 31### Possible investigation steps
 32
 33- Identify the principal and application using `azure.platformlogs.identity.claim.oid` and `azure.platformlogs.identity.claim.appid`. Use `azure.platformlogs.identity.claim.iss` to establish the issuing tenant, and resolve the object against the tenant's identity inventory.
 34- Review `Esql.time_window`, `Esql.secret_read_count`, `Esql.vault_count`, `Esql.vaults`, and `Esql.source_ips` to establish the access volume, affected vaults, and request sources.
 35- Review the original events and the `azure.platformlogs.properties.requestUri` and `azure.platformlogs.properties.id` values to identify the secrets accessed. Confirm successful retrieval using `azure.platformlogs.properties.httpStatusCode`; the normalized event outcome alone may not distinguish reads from denials.
 36- Determine whether the principal is an application, managed identity, or user acting through an application. Application and object claims can also appear in delegated tokens, and an absent user principal name does not establish app-only authentication.
 37- Correlate the activity with service-principal or managed-identity sign-ins, recent credential additions, permission changes, and access to services that use the retrieved secrets.
 38- Check whether the application owner expected a multi-vault inventory, migration, or deployment during the alert window.
 39
 40### False positive analysis
 41
 42- Authorized inventory, migration, and multi-vault deployment pipelines can produce this pattern. Compare the vault set and sources with the application's normal activity and change records.
 43- Scope any justified exception to the issuer, principal, application, and expected vault set, and reassess it when ownership or permissions change.
 44
 45### Response and remediation
 46
 47- If compromise is confirmed, restrict the principal's access to the affected vaults and remove compromised application credentials according to the incident response process.
 48- Determine which secrets were exposed and rotate them, including credentials for downstream services where necessary.
 49- Review and remove unauthorized permissions or credentials associated with the principal. Verify that access is denied after containment; removing an application credential alone does not immediately invalidate every issued access token.
 50- Preserve the relevant Key Vault, sign-in, and audit events for investigation.
 51"""
 52references = [
 53    "https://www.microsoft.com/en-us/security/blog/2026/10/21/storm-0940-uses-artex-agentic-ai-connectwise-supply-chain-compromise/",
 54    "https://learn.microsoft.com/en-us/azure/key-vault/general/logging",
 55]
 56risk_score = 47
 57rule_id = "e12f9b6a-1624-4670-a4cc-15cf4bc0b276"
 58setup = """#### Azure Key Vault AuditEvent Logs
 59
 60Enable AuditEvent diagnostic logging for the relevant Key Vaults and ingest it through the Azure integration's
 61platform logs data stream into `logs-azure.platformlogs-*`. Retain the token issuer, object ID, application ID,
 62vault resource ID, and HTTP status in the original events. The HTTP status is a subfield of the flattened
 63`azure.platformlogs.properties` field and is selected with KQL. Events missing the required identity or vault
 64fields are excluded. A user principal name is not required.
 65
 66The rule evaluates a 30-minute ingestion lookback every five minutes and groups requests into fixed 15-minute
 67event-time windows. Requests split across window boundaries or ingested more than 30 minutes apart may not be
 68combined. Review delivery latency and repeated aggregate alerts when tuning the schedule.
 69"""
 70severity = "medium"
 71tags = [
 72    "Domain: Cloud",
 73    "Domain: Identity",
 74    "Data Source: Azure",
 75    "Data Source: Azure Platform Logs",
 76    "Use Case: Threat Detection",
 77    "Tactic: Credential Access",
 78    "Resources: Investigation Guide",
 79    "Rule Type: ES|QL",
 80    "Platform: Azure",
 81    "Service: Azure Key Vault",
 82]
 83timestamp_override = "event.ingested"
 84type = "esql"
 85
 86query = '''
 87from logs-azure.platformlogs-* metadata _id, _index
 88| where data_stream.dataset == "azure.platformlogs"
 89  and event.action == "SecretGet"
 90  and azure.platformlogs.identity.claim.iss is not null and azure.platformlogs.identity.claim.iss != ""
 91  and azure.platformlogs.identity.claim.oid is not null and azure.platformlogs.identity.claim.oid != ""
 92  and azure.platformlogs.identity.claim.appid is not null and azure.platformlogs.identity.claim.appid != ""
 93  and azure.resource.id is not null and azure.resource.id != ""
 94  and KQL("azure.platformlogs.properties.httpStatusCode:200")
 95| eval Esql.time_window = date_trunc(15 minutes, @timestamp)
 96| stats
 97    Esql.secret_read_count = count(*),
 98    Esql.vault_count = count_distinct(azure.resource.id),
 99    Esql.vaults = values(azure.resource.id),
100    Esql.source_ips = values(source.ip),
101    Esql.first_seen = min(@timestamp),
102    Esql.last_seen = max(@timestamp)
103  by Esql.time_window, azure.platformlogs.identity.claim.iss, azure.platformlogs.identity.claim.oid,
104    azure.platformlogs.identity.claim.appid
105| where Esql.secret_read_count >= 20 and Esql.vault_count >= 3
106| keep azure.platformlogs.identity.claim.iss, azure.platformlogs.identity.claim.oid,
107    azure.platformlogs.identity.claim.appid, Esql.*
108'''
109
110
111[[rule.threat]]
112framework = "MITRE ATT&CK"
113[[rule.threat.technique]]
114id = "T1555"
115name = "Credentials from Password Stores"
116reference = "https://attack.mitre.org/techniques/T1555/"
117[[rule.threat.technique.subtechnique]]
118id = "T1555.006"
119name = "Cloud Secrets Management Stores"
120reference = "https://attack.mitre.org/techniques/T1555/006/"
121
122
123
124[rule.threat.tactic]
125id = "TA0006"
126name = "Credential Access"
127reference = "https://attack.mitre.org/tactics/TA0006/"
128
129[rule.investigation_fields]
130field_names = [
131    "azure.platformlogs.identity.claim.iss",
132    "azure.platformlogs.identity.claim.oid",
133    "azure.platformlogs.identity.claim.appid",
134    "Esql.secret_read_count",
135    "Esql.vault_count",
136    "Esql.vaults",
137    "Esql.time_window",
138]

Triage and analysis

Investigating Azure Key Vault Multi-Vault Secret Retrieval Burst by Application

Azure Key Vault stores credentials that applications use to access other services. A compromised identity can use its existing vault permissions to collect these credentials and extend access to additional resources. This rule matches the Storm-0940 hunting pattern: at least 20 successful SecretGet requests by one principal and application across at least three vaults in a 15-minute window. Single-vault application startup and refresh traffic is outside this threshold. Repeated reads of the same secret still count toward the volume.

Possible investigation steps

  • Identify the principal and application using azure.platformlogs.identity.claim.oid and azure.platformlogs.identity.claim.appid. Use azure.platformlogs.identity.claim.iss to establish the issuing tenant, and resolve the object against the tenant's identity inventory.
  • Review Esql.time_window, Esql.secret_read_count, Esql.vault_count, Esql.vaults, and Esql.source_ips to establish the access volume, affected vaults, and request sources.
  • Review the original events and the azure.platformlogs.properties.requestUri and azure.platformlogs.properties.id values to identify the secrets accessed. Confirm successful retrieval using azure.platformlogs.properties.httpStatusCode; the normalized event outcome alone may not distinguish reads from denials.
  • Determine whether the principal is an application, managed identity, or user acting through an application. Application and object claims can also appear in delegated tokens, and an absent user principal name does not establish app-only authentication.
  • Correlate the activity with service-principal or managed-identity sign-ins, recent credential additions, permission changes, and access to services that use the retrieved secrets.
  • Check whether the application owner expected a multi-vault inventory, migration, or deployment during the alert window.

False positive analysis

  • Authorized inventory, migration, and multi-vault deployment pipelines can produce this pattern. Compare the vault set and sources with the application's normal activity and change records.
  • Scope any justified exception to the issuer, principal, application, and expected vault set, and reassess it when ownership or permissions change.

Response and remediation

  • If compromise is confirmed, restrict the principal's access to the affected vaults and remove compromised application credentials according to the incident response process.
  • Determine which secrets were exposed and rotate them, including credentials for downstream services where necessary.
  • Review and remove unauthorized permissions or credentials associated with the principal. Verify that access is denied after containment; removing an application credential alone does not immediately invalidate every issued access token.
  • Preserve the relevant Key Vault, sign-in, and audit events for investigation.

References

Related rules

to-top