messaging-publish-triggers-consumer
Publishing/sending to an event source triggers the consumer bound to it (via an event-source-mapping/subscription/rule target) with an attacker-influenced payload.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_class(?src) in [Messaging, Storage]
node_class(?consumer) == Compute or node_type(?consumer) ==
Workflow
optional
Present → upgrade the emitted state; absent → downgrade (not a hard requirement).
{'principal': None}
CanSchedule {'src': None}
emit
| source type | Messaging |
|---|---|
| target type | Compute |
| source | ?principal |
| target | ?consumer |
| conditions | trigger_exists service_state |
| state logic | ACTIVE when the event-source binding is confirmed present and the consumer is invocable — the event-source-mapping is ENABLED, the subscription is ACTIVE, or the rule is ENABLED — so a published message actually drives a run. Otherwise CONDITIONAL(trigger_exists): the principal can publish but the binding is disabled/absent (then matched(optional[0]) — the principal can also create/enable the binding — keeps it realizable as CONDITIONAL, not BLOCKED). A source event filter / subscription filter the attacker payload CANNOT satisfy downgrades to CONDITIONAL(condition_expression) or BLOCKED. Inherit weakest with the contributing CanWriteData (a resource-policy/deny-gated publish caps this) and the CanTrigger binding edge. |
Narrative
{principal.name} can publish to the event source {src.name} ({perm:CanWriteData}), which is bound to {consumer.name} via an event-source mapping/subscription/rule; a crafted message therefore triggers {consumer.name} to run with an attacker-influenced payload.
Raw rule rules/derived/messaging-chains.yaml
id: messaging-publish-triggers-consumer
emits: CanTrigger
description: Publishing/sending to an event source triggers the consumer bound to it (via an event-source-mapping/subscription/rule
target) with an attacker-influenced payload.
applies_to:
- '*'
match:
- - principal: null
- CanWriteData
- src: null
- - src: null
- CanTrigger
- consumer: null
where:
- node_class(?src) in [Messaging, Storage]
- node_class(?consumer) == Compute or node_type(?consumer) == Workflow
optional:
- - principal: null
- CanSchedule
- src: null
emit:
source_type: Messaging
target_type: Compute
source: ?principal
target: ?consumer
permissions: []
conditions:
- trigger_exists
- service_state
state_logic: "ACTIVE when the event-source binding is confirmed present and the consumer is invocable\
\ \u2014 the event-source-mapping is ENABLED, the subscription is ACTIVE, or the rule is ENABLED \u2014\
\ so a published message actually drives a run. Otherwise CONDITIONAL(trigger_exists): the principal\
\ can publish but the binding is disabled/absent (then matched(optional[0]) \u2014 the principal can\
\ also create/enable the binding \u2014 keeps it realizable as CONDITIONAL, not BLOCKED). A source\
\ event filter / subscription filter the attacker payload CANNOT satisfy downgrades to CONDITIONAL(condition_expression)\
\ or BLOCKED. Inherit weakest with the contributing CanWriteData (a resource-policy/deny-gated publish\
\ caps this) and the CanTrigger binding edge."
confidence: min(contributing_confidences)
derived_from:
- ?principal CanWriteData ?src
- ?src CanTrigger ?consumer
false_positive_note: "The judgment is (a) the principal can genuinely PUBLISH to ?src (the send action\
\ \u2014 sqs:SendMessage / sns:Publish / events:PutEvents / kinesis:PutRecord / pubsub.topics.publish\
\ / ServiceBus/EventGrid/EventHub send \u2014 is granted, not denied by a resource policy) and (b)\
\ a LIVE binding routes ?src to ?consumer. Do NOT emit ACTIVE for a disabled event-source-mapping,\
\ an inactive/expired subscription, or a rule whose event pattern the attacker payload cannot match\
\ \u2014 an event-pattern/subscription filter is a real control (downgrade to CONDITIONAL/BLOCKED).\
\ A dead-letter-only or archive-only source that never invokes compute is not this edge. This CanTrigger\
\ feeds rule 2 (and cicd-chains rule 2 where the consumer is a CI runner) for the execute-as consequence;\
\ it does NOT by itself grant an identity."
narrative: '{principal.name} can publish to the event source {src.name} ({perm:CanWriteData}), which
is bound to {consumer.name} via an event-source mapping/subscription/rule; a crafted message therefore
triggers {consumer.name} to run with an attacker-influenced payload.'