azure-appconfig-listkeys-exposes-connstring
A principal with listKeys/action obtains the store's access-key connection strings (unless local auth is disabled).
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
{'principal': None}
HasPermission {'store': None}
{'store': None} Contains {'dataplane': None}
{'dataplane': None} ContainsCredential {'connstring': None}
where
node_class(?store) == ManagementService
provider_type(?store) == 'Microsoft.AppConfiguration/configurationStores'
node_class(?dataplane) == Data
?dataplane is the store's data plane (all key-values)
node_type(?connstring) ==
Credential # ExposesCredential target set is [Credential, Identity]; ConnectionString (a Secret-class subtype) is NOT a valid target. The explicit rule azure-appconfig-access-keys-present materializes the access-key connection strings as Credential nodes.
?principal has EFFECTIVE Microsoft.AppConfiguration/configurationStores/listKeys/action at the store scope (Contributor / Owner / custom role)
emit
| source | ?dataplane |
|---|---|
| target | ?connstring |
| permissions | Microsoft.AppConfiguration/configurationStores/listKeys/action |
| conditions | iam_permission service_state |
| state logic | ACTIVE if disableLocalAuth == false (access keys enabled) AND the principal holds listKeys/action. BLOCKED if disableLocalAuth == true (listKeys returns an empty list — no credential to expose). If disableLocalAuth is unknown, POTENTIAL(service_state). |
Narrative
The data plane of {store.name} exposes its access-key connection string(s) to any principal with listKeys (Contributor/Owner); access keys are enabled.
Raw rule rules/derived/azure/appconfig.yaml
id: azure-appconfig-listkeys-exposes-connstring
emits: ExposesCredential
description: A principal with listKeys/action obtains the store's access-key connection strings (unless
local auth is disabled).
match:
- - principal: null
- HasPermission
- store: null
- - store: null
- Contains
- dataplane: null
- - dataplane: null
- ContainsCredential
- connstring: null
where:
- node_class(?store) == ManagementService
- provider_type(?store) == 'Microsoft.AppConfiguration/configurationStores'
- node_class(?dataplane) == Data
- ?dataplane is the store's data plane (all key-values)
- 'node_type(?connstring) == Credential # ExposesCredential target set is [Credential, Identity]; ConnectionString
(a Secret-class subtype) is NOT a valid target. The explicit rule azure-appconfig-access-keys-present
materializes the access-key connection strings as Credential nodes.'
- ?principal has EFFECTIVE Microsoft.AppConfiguration/configurationStores/listKeys/action at the store
scope (Contributor / Owner / custom role)
emit:
source: ?dataplane
target: ?connstring
permissions:
- Microsoft.AppConfiguration/configurationStores/listKeys/action
conditions:
- iam_permission
- service_state
state_logic: "ACTIVE if disableLocalAuth == false (access keys enabled) AND the principal holds listKeys/action.\
\ BLOCKED if disableLocalAuth == true (listKeys returns an empty list \u2014 no credential to expose).\
\ If disableLocalAuth is unknown, POTENTIAL(service_state)."
confidence: '0.95'
derived_from:
- ?principal HasPermission ?store (listKeys/action)
- ?store Contains ?dataplane
- ?dataplane ContainsCredential ?connstring
false_positive_note: "BLOCKED when disableLocalAuth=true \u2014 do not emit an exposed connection string\
\ that does not exist. This is the credential-leak fact; the actual data read is modeled by azure-appconfig-connstring-reads-all-kv.\
\ Do NOT invoke listKeys during collection to confirm \u2014 infer from role assignments + disableLocalAuth.\
\ ExposesCredential source is the store's Data-plane node, not the ManagementService store object\
\ (schema source-set conformance)."
narrative: The data plane of {store.name} exposes its access-key connection string(s) to any principal
with listKeys (Contributor/Owner); access keys are enabled.