aws-keyspaces-restore-exfiltrate
cassandra:Restore on a source table + cassandra:Create + cassandra:Select on the target keyspace permits PITR-based table copy exfiltration: attacker restores source table data to a new table they control and can read via cassandra:Select.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
{'principal': None}
HasPermission {'source_table': None}
{'principal': None} HasPermission {'keyspace': None}
where
node_type(?source_table) ==
NoSQLDatabase
?source_table.provider_type == 'AWS::Cassandra::Table'
?source_table.pointInTimeRecovery.status == 'ENABLED'
effective_action(?principal, ?source_table) includes 'cassandra:Restore'
node_type(?keyspace) == NoSQLDatabase
?keyspace.provider_type == 'AWS::Cassandra::Keyspace'
effective_action(?principal, ?keyspace) includes 'cassandra:Create'
effective_action(?principal, ?keyspace) includes 'cassandra:Select'
emit
| source type | Identity |
|---|---|
| target type | NoSQLDatabase |
| source | ?principal |
| target | ?source_table |
| permissions | cassandra:Restore cassandra:Create cassandra:Select |
| conditions | iam_permission |
| state logic | ACTIVE when the principal holds IAM-effective cassandra:Restore on the source table ARN, cassandra:Create on the target keyspace ARN, AND cassandra:Select on the target keyspace ARN (Select at keyspace level covers all tables in the keyspace including the restored one). The source table must have pointInTimeRecovery.status == ENABLED. This is an exfiltration vector: the principal can restore the full table history to a new table within the keyspace and query that restored table to read all historical data. Without confirmed Select permission on the destination keyspace, the edge should be emitted as CONDITIONAL(iam_permission) — the attacker can copy the data but cannot yet read the restored copy. |
Narrative
{principal.name} can restore {source_table.name} from point-in-time backup to a new table in the same keyspace (cassandra:Restore + cassandra:Create) and read the restored table (cassandra:Select on keyspace), effectively exfiltrating all historical data in {source_table.name} to an attacker-controlled, queryable table.
Raw rule rules/derived/aws/keyspaces.yaml
id: aws-keyspaces-restore-exfiltrate
emits: CanReadData
description: 'cassandra:Restore on a source table + cassandra:Create + cassandra:Select on the target
keyspace permits PITR-based table copy exfiltration: attacker restores source table data to a new table
they control and can read via cassandra:Select.'
match:
- - principal: null
- HasPermission
- source_table: null
- - principal: null
- HasPermission
- keyspace: null
where:
- node_type(?source_table) == NoSQLDatabase
- ?source_table.provider_type == 'AWS::Cassandra::Table'
- ?source_table.pointInTimeRecovery.status == 'ENABLED'
- effective_action(?principal, ?source_table) includes 'cassandra:Restore'
- node_type(?keyspace) == NoSQLDatabase
- ?keyspace.provider_type == 'AWS::Cassandra::Keyspace'
- effective_action(?principal, ?keyspace) includes 'cassandra:Create'
- effective_action(?principal, ?keyspace) includes 'cassandra:Select'
emit:
source_type: Identity
target_type: NoSQLDatabase
source: ?principal
target: ?source_table
permissions:
- cassandra:Restore
- cassandra:Create
- cassandra:Select
conditions:
- iam_permission
state_logic: "ACTIVE when the principal holds IAM-effective cassandra:Restore on the source table ARN,\
\ cassandra:Create on the target keyspace ARN, AND cassandra:Select on the target keyspace ARN (Select\
\ at keyspace level covers all tables in the keyspace including the restored one). The source table\
\ must have pointInTimeRecovery.status == ENABLED. This is an exfiltration vector: the principal can\
\ restore the full table history to a new table within the keyspace and query that restored table\
\ to read all historical data. Without confirmed Select permission on the destination keyspace, the\
\ edge should be emitted as CONDITIONAL(iam_permission) \u2014 the attacker can copy the data but\
\ cannot yet read the restored copy."
confidence: contributing_confidence * 0.85
derived_from:
- <HasPermission edge for cassandra:Restore on ?source_table>
- <HasPermission edge for cassandra:Create on ?keyspace>
- <HasPermission edge for cassandra:Select on ?keyspace>
false_positive_note: PITR restore is only available if the source table has point-in-time recovery enabled
(?source_table.pointInTimeRecovery.status == ENABLED). The collector should verify this via GetTable.
cassandra:Restore scoped to a specific table ARN is required; a generic wildcard grant on tables must
still match the source table resource. cassandra:Create and cassandra:Select scoped to the keyspace
ARN are sufficient (no per-table Create or Select actions exist; keyspace-level grants cover all tables
in that keyspace).
narrative: '{principal.name} can restore {source_table.name} from point-in-time backup to a new table
in the same keyspace (cassandra:Restore + cassandra:Create) and read the restored table (cassandra:Select
on keyspace), effectively exfiltrating all historical data in {source_table.name} to an attacker-controlled,
queryable table.'