aws-elasticache-network-reach-no-auth
A Redis/Valkey cluster with AuthTokenEnabled=false (or absent) or a Memcached cluster is accessible to any VPC-reachable compute resource with an inbound security group rule on the cache port (6379 Redis, 11211 Memcached) - no credential is required. Both read and write operations are permitted without authentication, enabling cache poisoning and lateral movement attacks.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
generic_type(?cache) ==
Cache
class(?compute) in [Compute]
?cache.provider_type in ['AWS::ElastiCache::ReplicationGroup', 'AWS::ElastiCache::CacheCluster', 'AWS::ElastiCache::ServerlessCache']
(?cache.properties.Engine == 'memcached') OR (?cache.properties.Engine in ['redis', 'valkey']
AND (?cache.properties.AuthTokenEnabled == false
OR ?cache.properties.AuthTokenEnabled is null or absent)
AND (?cache.properties.UserGroupIds is null or empty))
# Redis/Valkey with AuthTokenEnabled=false OR no UserGroup attached == no auth
emit
Raw rule rules/derived/aws/elasticache.yaml
id: aws-elasticache-network-reach-no-auth
emits:
- CanReadData
- CanWriteData
description: "A Redis/Valkey cluster with AuthTokenEnabled=false (or absent) or a Memcached cluster is\
\ accessible to any VPC-reachable compute resource with an inbound security group rule on the cache\
\ port (6379 Redis, 11211 Memcached) \u2014 no credential is required. Both read and write operations\
\ are permitted without authentication, enabling cache poisoning and lateral movement attacks."
match:
- - compute: null
- CanNetworkReach
- cache: null
where:
- generic_type(?cache) == Cache
- class(?compute) in [Compute]
- ?cache.provider_type in ['AWS::ElastiCache::ReplicationGroup', 'AWS::ElastiCache::CacheCluster', 'AWS::ElastiCache::ServerlessCache']
- "(?cache.properties.Engine == 'memcached') OR (?cache.properties.Engine in ['redis', 'valkey']\n \
\ AND (?cache.properties.AuthTokenEnabled == false\n OR ?cache.properties.AuthTokenEnabled is\
\ null or absent)\n AND (?cache.properties.UserGroupIds is null or empty))\n# Redis/Valkey with AuthTokenEnabled=false\
\ OR no UserGroup attached == no auth"
emit:
- source_type: Compute
target_type: Cache
source: ?compute
target: ?cache
permissions: []
conditions:
- network_reachability
- service_state
state_logic: "CONDITIONAL(network_reachability): the cache is readable without a credential IF network\
\ reachability is confirmed (VPC compute in the same VPC/peered VPC with an SG inbound rule allowing\
\ TCP on the cache port from the compute resource's security group or CIDR). Upgrade to ACTIVE only\
\ when a CanNetworkReach or CanReachPort edge has been derived confirming TCP access on port 6379\
\ (Redis/Valkey) or 11211 (Memcached) between ?compute and ?cache. CONDITIONAL(service_state) when\
\ the cluster is in a non-AVAILABLE state (creating, modifying, deleting). BLOCKED when the cache\
\ engine enforces auth (AuthTokenEnabled=true OR UserGroupIds is non-empty for Redis/Valkey) \u2014\
\ in that case knowledge of the credential is the gate, not network reachability."
confidence: min(contributing_confidences) * 0.85
edge_type: CanReadData
derived_from:
- ?compute CanNetworkReach ?cache (port 6379 or 11211 confirmed reachable)
- ?cache.properties.AuthTokenEnabled == false or absent (DescribeReplicationGroups / DescribeCacheClusters
evidence)
false_positive_note: "The most critical gate for this rule is the AUTH status. Check: (1) For Redis/Valkey\
\ replication groups: DescribeReplicationGroups returns\n AuthTokenEnabled (bool). If true or if\
\ UserGroupIds is non-empty,\n auth is ON \u2014 do NOT emit ACTIVE; emit BLOCKED or do not emit.\n\
(2) For single-node Redis clusters (DescribeCacheClusters): AuthTokenEnabled\n field is present\
\ on the cache cluster object.\n(3) For Memcached: always no auth \u2014 emit regardless of the field\
\ value. (4) For Serverless: check UserGroupId in DescribeServerlessCaches. The network_reachability\
\ condition is MANDATORY \u2014 ElastiCache is VPC-only. Do NOT emit ACTIVE without a confirmed CanNetworkReach\
\ or CanReachPort edge for the relevant port from a specific compute resource. KMS at-rest encryption\
\ does NOT block wire-protocol access \u2014 it encrypts the underlying disk, not the Redis protocol.\
\ Do not add key_permission as a condition for this rule. A Redis cluster using TLS (TransitEncryptionEnabled=true)\
\ still uses the same AUTH token / ACL mechanism; TLS alone does not grant or deny data access."
narrative: '{cache.name} is a {cache.properties.Engine} cluster with no AUTH requirement and is network-reachable
from {compute.name} (TCP port {port}). Any code running on {compute.name} can connect to {cache.name}
and read all cached data without providing any credential.'
- source_type: Compute
target_type: Cache
source: ?compute
target: ?cache
permissions: []
conditions:
- network_reachability
- service_state
state_logic: "CONDITIONAL(network_reachability): the cache is fully writable without a credential IF\
\ network reachability is confirmed. A no-auth Redis/Memcached cluster permits any write operation\
\ \u2014 poisoning session caches, injecting template data, or corrupting application state. This\
\ enables lateral movement through cache-based attacks. Upgrade to ACTIVE when CanNetworkReach or\
\ CanReachPort is derived. CONDITIONAL(service_state) for non-AVAILABLE clusters. BLOCKED when auth\
\ is enforced."
confidence: min(contributing_confidences) * 0.85
edge_type: CanWriteData
derived_from:
- ?compute CanNetworkReach ?cache (port 6379 or 11211 confirmed reachable)
- ?cache.properties.AuthTokenEnabled == false or absent (DescribeReplicationGroups / DescribeCacheClusters
evidence)
false_positive_note: "Same AUTH status gates as CanReadData apply. No-auth Redis/Memcached clusters\
\ permit unrestricted write operations \u2014 this CanWriteData path models cache-poisoning and lateral\
\ movement attacks via stored cache data."
narrative: "{cache.name} is a {cache.properties.Engine} cluster with no AUTH requirement and is network-reachable\
\ from {compute.name} (TCP port {port}). Any code running on {compute.name} can connect to {cache.name}\
\ and write all cached data without providing any credential \u2014 full cache modification via network\
\ reachability alone, enabling cache poisoning and lateral movement."