aws-ebs-direct-api-exfil

EBS direct API read on a cross-account shared snapshot constitutes data exfiltration: the caller reads another account's disk data from their own account without ever launching an EC2 instance in the source account. This rule chains CanReadData on a cross-account snapshot into CanExfiltrate.

derived aws emits CanExfiltrate

match

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

{'principal': None} CanReadData {'snapshot': None}

where

node_type(?snapshot) == Snapshot ?snapshot.owner_account != ?principal.account

emit

source typeIdentity
target typeSnapshot
source?principal
target?snapshot
permissionsebs:ListSnapshotBlocks ebs:GetSnapshotBlock
conditionsiam_permission key_permission
state logicInherit from aws-ebs-direct-api-read CanReadData: ACTIVE if the CanReadData edge is ACTIVE, CONDITIONAL if gated by key_permission or other conditions. The CanExfiltrate edge summarizes the meaningful capability: data from another account CAN be exfiltrated, regardless of which rule (ebs direct API, volume mount, etc.) produced the CanReadData edge. Do NOT filter on rule_id provenance.

Narrative

{principal.name} can read blocks of {snapshot.name} (owned by a different account) via ebs:GetSnapshotBlock, constituting cross-account data exfiltration without any EC2 instance running in the source account.

Raw rule rules/derived/aws/ebs.yaml

id: aws-ebs-direct-api-exfil
emits: CanExfiltrate
description: 'EBS direct API read on a cross-account shared snapshot constitutes data exfiltration: the
  caller reads another account''s disk data from their own account without ever launching an EC2 instance
  in the source account. This rule chains CanReadData on a cross-account snapshot into CanExfiltrate.'
match:
- - principal: null
  - CanReadData
  - snapshot: null
where:
- node_type(?snapshot) == Snapshot
- ?snapshot.owner_account != ?principal.account
emit:
  source_type: Identity
  target_type: Snapshot
  source: ?principal
  target: ?snapshot
  permissions:
  - ebs:ListSnapshotBlocks
  - ebs:GetSnapshotBlock
  conditions:
  - iam_permission
  - key_permission
  state_logic: 'Inherit from aws-ebs-direct-api-read CanReadData: ACTIVE if the CanReadData edge is ACTIVE,
    CONDITIONAL if gated by key_permission or other conditions. The CanExfiltrate edge summarizes the
    meaningful capability: data from another account CAN be exfiltrated, regardless of which rule (ebs
    direct API, volume mount, etc.) produced the CanReadData edge. Do NOT filter on rule_id provenance.'
  confidence: 0.9
  derived_from:
  - <CanReadData edge on ?snapshot where ?snapshot.owner_account != ?principal.account>
  false_positive_note: "Only emit when the snapshot genuinely belongs to a different account (cross- account\
    \ data boundary crossing). If the snapshot is in the same account, the CanReadData edge is still real\
    \ but it is not an exfiltration \u2014 omit CanExfiltrate and emit only CanReadData. All CMEK caveats\
    \ from aws-ebs-direct-api-read apply. The CanReadData edge may be produced by any rule (direct API,\
    \ volume mount, etc.); this rule does NOT require provenance from a specific rule."
  narrative: '{principal.name} can read blocks of {snapshot.name} (owned by a different account) via ebs:GetSnapshotBlock,
    constituting cross-account data exfiltration without any EC2 instance running in the source account.'
move · open · esc close