azure-evg-subscription-triggers-compute

An active Event Grid event subscription binds a topic to a Compute consumer (Azure Function, Logic App, webhook); this is the CanTrigger fact consumed by messaging-chains rule 1.

derived azure emits CanTrigger

match

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

{'subscription': None} HasPolicy {'topic': None}

where

node_type(?subscription) == EventRule node_type(?topic) == EventBus ?subscription.properties.provisioningState == Succeeded ?subscription.properties.destination.endpointType in [AzureFunction, WebHook] (Compute consumers only) ?consumer is the Compute node at the destination endpoint (ServerlessFunction for AzureFunction, Webhook for WebHook)

emit

source typeEventBus
target typeCompute
source?topic
target?consumer
conditionsservice_state condition_expression
state logicCONDITIONAL(service_state, condition_expression) when the subscription provisioningState=Succeeded. The edge is base-CONDITIONAL because real-world traversal depends on: (1) the consumer being running/reachable (service_state), and (2) the event type filter on the subscription not blocking attacker-controlled event types (condition_expression). Downgrade to BLOCKED if provisioningState != Succeeded or the subscription is explicitly disabled. BLOCKED if delivery is suspended (e.g., dead-letter-only after max retry exhaustion). This is the structural CanTrigger binding fact — consumed by messaging-chains messaging-publish-triggers-consumer to derive CanTrigger(publisher->consumer).

Narrative

Event Grid topic {source.name} has an active event subscription routing events to Compute consumer {target.name}; publishing an event to {source.name} (with a matching event type and filter) triggers {target.name} with an attacker-controlled payload. messaging-chains messaging-publish-triggers-consumer consumes this CanTrigger fact together with CanWriteData on the topic to derive CanTrigger(publisher->consumer), then messaging-trigger-executes-as derives CanExecuteAs(consumer's identity).

Raw rule rules/derived/azure/eventgrid.yaml

id: azure-evg-subscription-triggers-compute
emits: CanTrigger
description: An active Event Grid event subscription binds a topic to a Compute consumer (Azure Function,
  Logic App, webhook); this is the CanTrigger fact consumed by messaging-chains rule 1.
match:
- - subscription: null
  - HasPolicy
  - topic: null
where:
- node_type(?subscription) == EventRule
- node_type(?topic) == EventBus
- ?subscription.properties.provisioningState == Succeeded
- ?subscription.properties.destination.endpointType in [AzureFunction, WebHook] (Compute consumers only)
- ?consumer is the Compute node at the destination endpoint (ServerlessFunction for AzureFunction, Webhook
  for WebHook)
emit:
  source_type: EventBus
  target_type: Compute
  source: ?topic
  target: ?consumer
  permissions: []
  conditions:
  - service_state
  - condition_expression
  state_logic: "CONDITIONAL(service_state, condition_expression) when the subscription provisioningState=Succeeded.\
    \ The edge is base-CONDITIONAL because real-world traversal depends on: (1) the consumer being running/reachable\
    \ (service_state), and (2) the event type filter on the subscription not blocking attacker-controlled\
    \ event types (condition_expression). Downgrade to BLOCKED if provisioningState != Succeeded or the\
    \ subscription is explicitly disabled. BLOCKED if delivery is suspended (e.g., dead-letter-only after\
    \ max retry exhaustion). This is the structural CanTrigger binding fact \u2014 consumed by messaging-chains\
    \ messaging-publish-triggers-consumer to derive CanTrigger(publisher->consumer)."
  confidence: 0.97
  derived_from:
  - Event subscription provisioningState=Succeeded with a Compute consumer endpoint
  - 'messaging-chains.yaml: messaging-publish-triggers-consumer (rule 1): CanWriteData(?p,?topic) + CanTrigger(?topic,?consumer)
    => CanTrigger(?p,?consumer)'
  - 'messaging-chains.yaml: messaging-trigger-executes-as (rule 2): CanTrigger(?p,?consumer) + ExecutesAs(?consumer,?id)
    => CanExecuteAs(?p,?id)'
  false_positive_note: "This edge is the raw event-source binding fact for COMPUTE CONSUMERS only (the\
    \ subscription routes topic events to the consumer). It does NOT by itself grant escalation \u2014\
    \ escalation requires a publisher (CanWriteData) on the topic AND a consumer that ExecutesAs an identity\
    \ (messaging-chains rules 1-2 provide the roll-up). Honor the event type filter: if the filter restricts\
    \ which events reach the consumer and the attacker cannot produce a matching event, the edge remains\
    \ CONDITIONAL (condition_expression) \u2014 messaging-chains will not derive CanTrigger(publisher->consumer)\
    \ unless the publisher can craft events matching the filter. For Messaging consumers (Service Bus,\
    \ Storage queue, Event Hub), emit CanWriteData instead, as the message lands in a further consumer's\
    \ event source. A consumer target of type Webhook is modeled as Webhook (Compute subtype); a consumer\
    \ target of type Azure Function is modeled as ServerlessFunction."
  narrative: Event Grid topic {source.name} has an active event subscription routing events to Compute
    consumer {target.name}; publishing an event to {source.name} (with a matching event type and filter)
    triggers {target.name} with an attacker-controlled payload. messaging-chains messaging-publish-triggers-consumer
    consumes this CanTrigger fact together with CanWriteData on the topic to derive CanTrigger(publisher->consumer),
    then messaging-trigger-executes-as derives CanExecuteAs(consumer's identity).
move · open · esc close