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.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
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 — 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.'