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.

derived aws emits CanReadData

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 typeIdentity
target typeNoSQLDatabase
source?principal
target?source_table
permissionscassandra:Restore cassandra:Create cassandra:Select
conditionsiam_permission
state logicACTIVE 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.'
move · open · esc close