aws-rds-restore-snapshot-yields-db-access

rds:RestoreDBInstanceFromDBSnapshot or rds:RestoreDBClusterFromSnapshot with a shared or public snapshot allows a principal to restore a full database copy as the master user - gaining superuser access to all data.

derived aws emits CanReadData

match

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

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

where

node_type(?snapshot) == Snapshot ?snapshot.provider_type in ['AWS::RDS::DBSnapshot', 'AWS::RDS::DBClusterSnapshot'] ?principal has EFFECTIVE rds:RestoreDBInstanceFromDBSnapshot (or rds:RestoreDBClusterFromSnapshot) on the snapshot ARN ?snapshot has CrossAccountTrust OR ExposedToInternet (public or cross-account snapshot sharing confirmed)

emit

source typeIdentity
target typeSnapshot
source?principal
target?snapshot
permissionsrds:RestoreDBInstanceFromDBSnapshot rds:RestoreDBClusterFromSnapshot
conditionsiam_permission scp_or_org_policy key_permission
state logicACTIVE when rds:RestoreDBInstanceFromDBSnapshot (or rds:RestoreDBClusterFromSnapshot) is confirmed EFFECTIVE on the snapshot ARN AND the snapshot is publicly restorable (ExposedToInternet to AnonymousIdentity) or shared to the principal's account (CrossAccountTrust confirmed). CONDITIONAL(key_permission) when the snapshot is encrypted with a CMK that is not shared to the restoring account — the principal can restore but cannot decrypt the restored DB without kms:Decrypt on the CMK. BLOCKED when an SCP or permission boundary denies rds:RestoreDBInstanceFromDBSnapshot.

Narrative

{principal.name} can restore the RDS snapshot {snapshot.name} into their own account as the master user (rds:RestoreDBInstanceFromDBSnapshot / rds:RestoreDBClusterFromSnapshot), gaining full superuser access to all data in the snapshot. This is a complete data exfiltration path when combined with public or cross-account snapshot sharing.

Raw rule rules/derived/aws/rds.yaml

id: aws-rds-restore-snapshot-yields-db-access
emits: CanReadData
description: "rds:RestoreDBInstanceFromDBSnapshot or rds:RestoreDBClusterFromSnapshot with a shared or\
  \ public snapshot allows a principal to restore a full database copy as the master user \u2014 gaining\
  \ superuser access to all data."
match:
- - principal: null
  - HasPermission
  - snapshot: null
where:
- node_type(?snapshot) == Snapshot
- ?snapshot.provider_type in ['AWS::RDS::DBSnapshot', 'AWS::RDS::DBClusterSnapshot']
- ?principal has EFFECTIVE rds:RestoreDBInstanceFromDBSnapshot (or rds:RestoreDBClusterFromSnapshot) on
  the snapshot ARN
- ?snapshot has CrossAccountTrust OR ExposedToInternet (public or cross-account snapshot sharing confirmed)
emit:
  source_type: Identity
  target_type: Snapshot
  source: ?principal
  target: ?snapshot
  permissions:
  - rds:RestoreDBInstanceFromDBSnapshot
  - rds:RestoreDBClusterFromSnapshot
  conditions:
  - iam_permission
  - scp_or_org_policy
  - key_permission
  state_logic: "ACTIVE when rds:RestoreDBInstanceFromDBSnapshot (or rds:RestoreDBClusterFromSnapshot)\
    \ is confirmed EFFECTIVE on the snapshot ARN AND the snapshot is publicly restorable (ExposedToInternet\
    \ to AnonymousIdentity) or shared to the principal's account (CrossAccountTrust confirmed). CONDITIONAL(key_permission)\
    \ when the snapshot is encrypted with a CMK that is not shared to the restoring account \u2014 the\
    \ principal can restore but cannot decrypt the restored DB without kms:Decrypt on the CMK. BLOCKED\
    \ when an SCP or permission boundary denies rds:RestoreDBInstanceFromDBSnapshot."
  confidence: min(contributing_confidences) * 0.90
  derived_from:
  - ?principal HasPermission ?snapshot (rds:RestoreDBInstanceFromDBSnapshot / RestoreDBClusterFromSnapshot)
  - ?snapshot ExposedToInternet OR CrossAccountTrust
  false_positive_note: "Restore capability is only exploitable if the snapshot is publicly restorable\
    \ (ExposedToInternet with AnonymousIdentity) or specifically shared to the attacker's account (CrossAccountTrust).\
    \ A private snapshot in the same account that the principal owns does not merit CanReadData via restore\
    \ \u2014 the principal already has access. Restore creates a NEW database instance/cluster as a copy;\
    \ the restoring principal becomes the master user of the restored DB. KMS-encrypted snapshots are\
    \ CONDITIONAL if the CMK is not shared. Restore may take several minutes; the edge is realized when\
    \ the restore completes and the DB is AVAILABLE."
  narrative: '{principal.name} can restore the RDS snapshot {snapshot.name} into their own account as
    the master user (rds:RestoreDBInstanceFromDBSnapshot / rds:RestoreDBClusterFromSnapshot), gaining
    full superuser access to all data in the snapshot. This is a complete data exfiltration path when
    combined with public or cross-account snapshot sharing.'
move · open · esc close