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.oidandazure.platformlogs.identity.claim.appid. Useazure.platformlogs.identity.claim.issto 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, andEsql.source_ipsto establish the access volume, affected vaults, and request sources. - Review the original events and the
azure.platformlogs.properties.requestUriandazure.platformlogs.properties.idvalues to identify the secrets accessed. Confirm successful retrieval usingazure.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
- Azure Key Vault Excessive Secret or Key Retrieved
- Azure Key Vault Unusual Secret Key Usage
- Multiple Cloud Secrets Accessed by Source Address
- Microsoft Graph Application Directory Reconnaissance with Denied Requests
- Entra ID Device-Bound PRT Replay via First-Party App from Unusual IP