aws-elasticache-snapshot-exfil

elasticache:CopySnapshot copies an existing Redis RDB snapshot to an S3 bucket. If the destination bucket is attacker-accessible, the RDB file - containing all cached in-memory data including application secrets - is exfiltrated. No live cluster access needed.

derived aws emits CanExfiltrate

match

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

{'principal': None} HasPermission {'snapshot': None}

where

generic_type(?snapshot) == Snapshot ?snapshot.provider_type == 'AWS::ElastiCache::Snapshot' ?principal has EFFECTIVE elasticache:CopySnapshot on ?snapshot ARN

emit

source typeIdentity
target typeSnapshot
source?principal
target?snapshot
permissionselasticache:CopySnapshot
conditionsiam_permission scp_or_org_policy resource_policy key_permission
state logicCONDITIONAL(resource_policy): ACTIVE only when the destination S3 bucket is also attacker-accessible (attacker controls the bucket OR a confirming CanWriteData edge to a bucket in the attacker's account exists). Without the S3 write gate, the snapshot is copyable but only to an account-internal destination — emit CONDITIONAL(resource_policy) to flag the capability while noting the destination gate. CONDITIONAL(key_permission) when the source snapshot is encrypted with a CMK: the CopySnapshot call succeeds, but reading the RDB content (S3 object) requires kms:Decrypt on the CMK — the attacker may need to request a cross-account key grant. BLOCKED when an SCP or permission boundary denies elasticache:CopySnapshot. CONDITIONAL(service_state) when the cluster is in a non-snapshotable state (multi-AZ or cluster mode clusters require the cluster to be available for the snapshot to exist and be copyable).

Narrative

{principal.name} can call elasticache:CopySnapshot to export the Redis snapshot {snapshot.name} to an S3 bucket as an RDB file. The RDB file is a complete serialized dump of all in-memory cache data at snapshot time, including any application secrets (session tokens, API keys, database passwords) stored by the application. An attacker who controls the destination S3 bucket can download and parse the RDB file offline to extract cached data without ever connecting to the live Redis cluster.

Raw rule rules/derived/aws/elasticache.yaml

id: aws-elasticache-snapshot-exfil
emits: CanExfiltrate
description: "elasticache:CopySnapshot copies an existing Redis RDB snapshot to an S3 bucket. If the destination\
  \ bucket is attacker-accessible, the RDB file \u2014 containing all cached in-memory data including\
  \ application secrets \u2014 is exfiltrated. No live cluster access needed."
match:
- - principal: null
  - HasPermission
  - snapshot: null
where:
- generic_type(?snapshot) == Snapshot
- ?snapshot.provider_type == 'AWS::ElastiCache::Snapshot'
- ?principal has EFFECTIVE elasticache:CopySnapshot on ?snapshot ARN
emit:
  source_type: Identity
  target_type: Snapshot
  source: ?principal
  target: ?snapshot
  permissions:
  - elasticache:CopySnapshot
  conditions:
  - iam_permission
  - scp_or_org_policy
  - resource_policy
  - key_permission
  state_logic: "CONDITIONAL(resource_policy): ACTIVE only when the destination S3 bucket is also attacker-accessible\
    \ (attacker controls the bucket OR a confirming CanWriteData edge to a bucket in the attacker's account\
    \ exists). Without the S3 write gate, the snapshot is copyable but only to an account-internal destination\
    \ \u2014 emit CONDITIONAL(resource_policy) to flag the capability while noting the destination gate.\
    \ CONDITIONAL(key_permission) when the source snapshot is encrypted with a CMK: the CopySnapshot call\
    \ succeeds, but reading the RDB content (S3 object) requires kms:Decrypt on the CMK \u2014 the attacker\
    \ may need to request a cross-account key grant. BLOCKED when an SCP or permission boundary denies\
    \ elasticache:CopySnapshot. CONDITIONAL(service_state) when the cluster is in a non-snapshotable state\
    \ (multi-AZ or cluster mode clusters require the cluster to be available for the snapshot to exist\
    \ and be copyable)."
  confidence: min(contributing_confidences) * 0.80
  derived_from:
  - ?principal HasPermission ?snapshot (elasticache:CopySnapshot effective permission)
  false_positive_note: "The S3 destination is the key gate. elasticache:CopySnapshot's DestinationS3Location\
    \ parameter specifies the bucket and prefix. The attacker must have a bucket that accepts the write\
    \ (bucket policy must allow s3:PutObject from the ElastiCache service principal or the caller's account).\
    \ Do NOT emit ACTIVE unless the destination bucket ownership is confirmed as attacker-accessible.\
    \ For encrypted snapshots (AtRestEncryptionEnabled with a CMK), the RDB data in S3 is KMS-encrypted;\
    \ the attacker additionally needs kms:Decrypt on the CMK or a cross-account key grant \u2014 add key_permission\
    \ condition for encrypted clusters. AWS-managed (default SSE-S3) snapshot encryption does NOT require\
    \ a key grant. This rule requires an existing snapshot \u2014 the elasticache:CreateSnapshot permission\
    \ is a prerequisite (or a snapshot is already scheduled/available); it is not modeled here. NOTE:\
    \ This rule is conservative by design (Phase-6 low-relevance guidance for ElastiCache: 1-3 rules).\
    \ The exfil path is real but requires two permissions (snapshot + S3 write) and is more complex than\
    \ the AUTH-token-reset path. Cached data in ElastiCache is often transient; impact depends on what\
    \ the application stores (session tokens expire, API keys may still be valid)."
  narrative: '{principal.name} can call elasticache:CopySnapshot to export the Redis snapshot {snapshot.name}
    to an S3 bucket as an RDB file. The RDB file is a complete serialized dump of all in-memory cache
    data at snapshot time, including any application secrets (session tokens, API keys, database passwords)
    stored by the application. An attacker who controls the destination S3 bucket can download and parse
    the RDB file offline to extract cached data without ever connecting to the live Redis cluster.'
move · open · esc close