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.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
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 |
| 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 — 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).