aws-sns-subscription-trigger
A confirmed active SNS subscription binds the topic to its consumer; every Publish invokes the consumer with the message payload.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?topic) ==
Topic
node_provider(?topic) == aws
node_type(?subscription) == EventRule # AWS::SNS::Subscription
?subscription.Protocol in [lambda, sqs] # Lambda and SQS are the compute/execution-relevant paths
?subscription.SubscriptionArn is confirmed (not PendingConfirmation, not Deleted)
?consumer is the node corresponding to ?subscription.Endpoint (lambda function ARN or SQS queue ARN)
emit
| source type | Topic |
|---|---|
| target type | Compute |
| source | ?topic |
| target | ?consumer |
| conditions | trigger_exists service_state |
| state logic | ACTIVE when the subscription SubscriptionArn is confirmed and not in PendingConfirmation or Deleted state, AND the consumer (Lambda function or SQS queue) is enabled/active. CONDITIONAL(trigger_exists) when the subscription exists but the consumer is disabled, throttled, or the event-source-mapping consuming the SQS queue is disabled. CONDITIONAL(condition_expression) when a non-empty FilterPolicy is set on the subscription — not all messages will be delivered; an attacker must craft a message whose attributes satisfy the filter. POTENTIAL(trigger_exists) for a pending (unconfirmed) subscription. Note: for SQS subscribers, the actual execution identity is on the SQS consumer (Lambda ESM, ECS poller) — this edge models the SNS-to-SQS delivery binding; the SQS-to-consumer binding is the SQS adapter's job. |
Narrative
SNS topic {topic.name} has a confirmed subscription to {consumer.name} (Protocol {subscription.Protocol}); every sns:Publish call fans out to {consumer.name}, invoking it with the message as payload. Combined with CanWriteData(publisher, topic) via messaging-chains rule 1, this derives CanTrigger(publisher, {consumer.name}).
Raw rule rules/derived/aws/sns.yaml
id: aws-sns-subscription-trigger
emits: CanTrigger
description: A confirmed active SNS subscription binds the topic to its consumer; every Publish invokes
the consumer with the message payload.
match:
- - topic: null
- HasPolicy
- subscription: null
where:
- node_type(?topic) == Topic
- node_provider(?topic) == aws
- 'node_type(?subscription) == EventRule # AWS::SNS::Subscription'
- '?subscription.Protocol in [lambda, sqs] # Lambda and SQS are the compute/execution-relevant paths'
- ?subscription.SubscriptionArn is confirmed (not PendingConfirmation, not Deleted)
- ?consumer is the node corresponding to ?subscription.Endpoint (lambda function ARN or SQS queue ARN)
emit:
source_type: Topic
target_type: Compute
source: ?topic
target: ?consumer
permissions: []
conditions:
- trigger_exists
- service_state
state_logic: "ACTIVE when the subscription SubscriptionArn is confirmed and not in PendingConfirmation\
\ or Deleted state, AND the consumer (Lambda function or SQS queue) is enabled/active. CONDITIONAL(trigger_exists)\
\ when the subscription exists but the consumer is disabled, throttled, or the event-source-mapping\
\ consuming the SQS queue is disabled. CONDITIONAL(condition_expression) when a non-empty FilterPolicy\
\ is set on the subscription \u2014 not all messages will be delivered; an attacker must craft a message\
\ whose attributes satisfy the filter. POTENTIAL(trigger_exists) for a pending (unconfirmed) subscription.\
\ Note: for SQS subscribers, the actual execution identity is on the SQS consumer (Lambda ESM, ECS\
\ poller) \u2014 this edge models the SNS-to-SQS delivery binding; the SQS-to-consumer binding is\
\ the SQS adapter's job."
confidence: 0.95
derived_from:
- ?topic HasPolicy ?subscription (confirmed active)
false_positive_note: "CRITICAL: only emit ACTIVE for subscriptions where SubscriptionArn is a real confirmed\
\ ARN (not the literal string \"PendingConfirmation\"). Pending subscriptions have not been confirmed\
\ by the endpoint and will NOT receive messages \u2014 downgrade to POTENTIAL(trigger_exists) at most.\
\ FilterPolicy: when a non-empty FilterPolicy is present, an attacker who cannot produce a message\
\ with matching MessageAttributes cannot trigger the consumer through normal delivery \u2014 downgrade\
\ to CONDITIONAL(condition_expression). Conservative default: treat any non-empty FilterPolicy as\
\ CONDITIONAL unless the FilterPolicy is verified to be trivially satisfiable by an arbitrary Publish\
\ call. FIFO topics (standard Lambda subscription not supported directly): do not emit CanTrigger(fifo_topic\
\ -> lambda) without a SQS FIFO intermediary."
narrative: SNS topic {topic.name} has a confirmed subscription to {consumer.name} (Protocol {subscription.Protocol});
every sns:Publish call fans out to {consumer.name}, invoking it with the message as payload. Combined
with CanWriteData(publisher, topic) via messaging-chains rule 1, this derives CanTrigger(publisher,
{consumer.name}).