azure-evg-publish-via-key

A principal that holds the topic access key (retrieved via listKeys/action) can publish arbitrary events to the topic over HTTPS, triggering all bound consumers.

derived azure emits CanWriteData

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

{'principal': None} CanReadSecret {'key': None}

where

node_type(?key) == AccessKey ?key is a topic access key (key1 or key2) for an Event Grid custom topic or domain topic ?topic is the Event Grid topic or domain that ?key authenticates to ?topic.properties.publicNetworkAccess == Enabled OR principal has network path to topic private endpoint

emit

source typeIdentity
target typeGenericData
source?principal
target?topic
conditionstrigger_exists network_reachability
state logicACTIVE when the key has been retrieved (CanReadSecret ACTIVE) AND the topic is network-reachable (publicNetworkAccess=Enabled, or principal has private endpoint access). CONDITIONAL(network_reachability) when the topic has publicNetworkAccess= Disabled and no confirmed private endpoint reach. CONDITIONAL(trigger_exists) when the topic has no confirmed live event subscription binding to a consumer (publishing succeeds but no consumer is triggered — still emitted at CONDITIONAL because a subscription may exist or be creatable). Inherit weakest from CanReadSecret. BLOCKED if the key has been rotated after retrieval (key is no longer valid) or if deny assignment blocks listKeys/action (which blocks the prerequisite CanReadSecret).

Narrative

{principal.name} holds the access key for Event Grid topic {target.name} (retrieved via topics/listKeys/action); it can publish arbitrary events over HTTPS (aeg-sas-key header), triggering all bound event subscription consumers with an attacker-controlled payload. messaging-chains derives CanTrigger(principal->consumer) from this CanWriteData + the existing subscription CanTrigger binding.

Raw rule rules/derived/azure/eventgrid.yaml

id: azure-evg-publish-via-key
emits: CanWriteData
description: A principal that holds the topic access key (retrieved via listKeys/action) can publish arbitrary
  events to the topic over HTTPS, triggering all bound consumers.
match:
- - principal: null
  - CanReadSecret
  - key: null
where:
- node_type(?key) == AccessKey
- ?key is a topic access key (key1 or key2) for an Event Grid custom topic or domain topic
- ?topic is the Event Grid topic or domain that ?key authenticates to
- ?topic.properties.publicNetworkAccess == Enabled OR principal has network path to topic private endpoint
emit:
  source_type: Identity
  target_type: GenericData
  source: ?principal
  target: ?topic
  permissions: []
  conditions:
  - trigger_exists
  - network_reachability
  state_logic: "ACTIVE when the key has been retrieved (CanReadSecret ACTIVE) AND the topic is network-reachable\
    \ (publicNetworkAccess=Enabled, or principal has private endpoint access). CONDITIONAL(network_reachability)\
    \ when the topic has publicNetworkAccess= Disabled and no confirmed private endpoint reach. CONDITIONAL(trigger_exists)\
    \ when the topic has no confirmed live event subscription binding to a consumer (publishing succeeds\
    \ but no consumer is triggered \u2014 still emitted at CONDITIONAL because a subscription may exist\
    \ or be creatable). Inherit weakest from CanReadSecret. BLOCKED if the key has been rotated after\
    \ retrieval (key is no longer valid) or if deny assignment blocks listKeys/action (which blocks the\
    \ prerequisite CanReadSecret)."
  confidence: min(contributing_confidences) * 0.97
  derived_from:
  - 'azure-evg-list-keys OR azure-evg-domain-list-keys: ?principal CanReadSecret ?key'
  - 'messaging-chains.yaml: messaging-publish-triggers-consumer: CanWriteData + CanTrigger(topic->consumer)
    => CanTrigger(principal->consumer)'
  false_positive_note: "Publishing via key does NOT require any ARM RBAC permission at publish time \u2014\
    \ it is HTTP authenticated using the key (aeg-sas-key header). The prerequisite is CanReadSecret (listKeys/action),\
    \ which retrieves the key. Once the key is in hand, the attacker can publish from any network endpoint\
    \ that can reach the topic's public endpoint or private endpoint. Do not list Microsoft.EventGrid/events/send/action\
    \ in permissions (that is Entra token-based publish, a different path). A topic with publicNetworkAccess=Disabled\
    \ cannot be published to from the internet regardless of key possession; downgrade to CONDITIONAL(network_reachability)\
    \ if no confirmed private endpoint access. The key enables unlimited publishing \u2014 no per-event\
    \ rate limit that would prevent triggering consumers. Publishing does NOT grant read access to consumer\
    \ endpoints (Service Bus queues, Storage queues). The consumer must have a live, enabled event subscription\
    \ binding for messaging-chains rule 1 to fire \u2014 verify the binding before marking the full CanTrigger\
    \ chain ACTIVE. System topics do not accept publish via key (only first-party services publish); do\
    \ not emit for system topics."
  narrative: '{principal.name} holds the access key for Event Grid topic {target.name} (retrieved via
    topics/listKeys/action); it can publish arbitrary events over HTTPS (aeg-sas-key header), triggering
    all bound event subscription consumers with an attacker-controlled payload. messaging-chains derives
    CanTrigger(principal->consumer) from this CanWriteData + the existing subscription CanTrigger binding.'
move · open · esc close