Replay Attack in Dynamodb
How Replay Attack Manifests in DynamoDB
Replay attacks in DynamoDB-backed APIs exploit predictable state tokens or insufficient request validation to repeat authenticated or unauthenticated actions. Unlike stateless REST APIs, DynamoDB's pagination and conditional operations create unique attack surfaces.
Pagination Token Replay (LastEvaluatedKey)
DynamoDB's Query and Scan operations return a LastEvaluatedKey for subsequent pages. If an API exposes this token without cryptographic binding to the user session, an attacker can capture and replay it to access data beyond their authorized scope. Consider a vulnerable Node.js endpoint:
// Vulnerable: returns raw DynamoDB pagination token
app.get('/api/users', async (req, res) => {
const result = await ddb.query({
TableName: 'Users',
IndexName: 'email-index',
KeyConditionExpression: 'email = :email',
ExpressionAttributeValues: { ':email': req.query.email },
ExclusiveStartKey: req.query.token // Directly uses client-provided token
}).promise();
res.json({ data: result.Items, nextToken: result.LastEvaluatedKey });
});An attacker with read access to user records can capture a nextToken for a paginated query, then replay it with a different email parameter to enumerate other users' data (CWE-294: Authentication Bypass by Capture-replay).
Conditional Write Replay via Timestamp-Based Conditions
DynamoDB's ConditionExpression often uses timestamps for optimistic locking. If the condition relies solely on a client-supplied timestamp (e.g., updatedAt <= :clientTime), an attacker can replay an old request after the data has changed, overwriting newer data. Vulnerable Python example:
# Vulnerable: client-provided timestamp in condition
@api.put('/items/{id}')
def update_item(id):
ddb.update_item(
TableName='Items',
Key={'id': id},
UpdateExpression='SET #val = :val, #ts = :ts',
ConditionExpression='attribute_not_exists(#ts) OR #ts <= :clientTs',
ExpressionAttributeValues={
':val': request.json['value'],
':ts': request.json['timestamp'], # Attacker-controlled
':clientTs': request.json['timestamp']
}
)An attacker intercepts a legitimate update request and replays it later, potentially reverting data to an old state.
Atomic Counter Manipulation
DynamoDB's UpdateItem with ADD> on numeric attributes (e.g., counters) lacks inherent replay protection. If an API uses a nonce from the client (like an order ID) without server-side tracking, replaying an ADD> request inflates counters. For instance, a POST /api/cart/increment that adds to a quantity field based on a client-provided cartId can be replayed to increase inventory counts fraudulently.
DynamoDB-Specific Detection
Detecting DynamoDB replay vulnerabilities requires analyzing both the API's contract (OpenAPI spec) and runtime behavior. Manual detection involves:
- Inspecting pagination tokens: Capture responses from
Query/Scanendpoints. If tokens are opaque (e.g., base64-encoded but not signed) and accepted across different user contexts, replay is likely. - Testing conditional writes: Send two sequential
UpdateItemrequests with the sameConditionExpressiontimestamp. If the second succeeds after the first modifies the item, the condition is flawed. - Reviewing atomic operations: Identify
ADD> actions on numeric attributes without server-generated nonces. Replay the request to check for cumulative effects.
Automated Scanning with middleBrick
middleBrick's black-box scanner tests for these patterns automatically. When you submit a DynamoDB-backed API endpoint:
- It performs BOLA/IDOR and Input Validation checks in parallel, probing pagination tokens and conditional writes.
- The scanner captures
LastEvaluatedKeytokens from one user context and replays them in another (or with altered query parameters) to test for horizontal privilege escalation. - For write endpoints, it sends duplicate
UpdateItemrequests with identical conditions to detect state corruption. - Findings are reported with a severity score (0–100) and mapped to OWASP API Top 10: API5:2023 — Broken Function Level Authorization and API8:2023 — Security Misconfiguration.
Example middleBrick JSON output snippet for a replay vulnerability:
{
"finding": "Pagination token accepted across user contexts",
"category": "BOLA/IDOR",
"severity": 85,
"evidence": {
"endpoint": "/api/orders",
"replayed_token": "{\"id\":\"order-123\",\"sk\":\"user-alice\"}",
"impact": "Access to other users' orders"
},
"remediation": "Sign pagination tokens with user-specific secret (e.g., HMAC) and validate on server."
}You can integrate middleBrick into CI/CD via its GitHub Action to catch these issues before deployment, or use the CLI tool (middlebrick scan <url>) for ad-hoc testing.
DynamoDB-Specific Remediation
Remediation leverages DynamoDB's native features to cryptographically bind requests to user sessions and enforce server-side state.
1. Sign Pagination Tokens
Never return raw LastEvaluatedKey. Instead, encrypt or sign it with a user-specific secret. Using AWS KMS or a server-side HMAC:
// Node.js with jsonwebtoken
const jwt = require('jsonwebtoken');
app.get('/api/users', async (req, res) => {
const result = await ddb.query({
TableName: 'Users',
ExclusiveStartKey: req.query.token
? jwt.verify(req.query.token, process.env.TOKEN_SECRET).key
: undefined
}).promise();
const signedToken = result.LastEvaluatedKey
? jwt.sign({ key: result.LastEvaluatedKey }, process.env.TOKEN_SECRET, { expiresIn: '5m' })
: null;
res.json({ data: result.Items, nextToken: signedToken });
});The token expires quickly and is invalid if tampered with or replayed in a different session.
2. Server-Side Nonces for Conditional Writes
Generate a unique, single-use nonce (e.g., UUID) stored in DynamoDB with the item. The ConditionExpression requires the nonce to match and then deletes it atomically:
// Python (boto3) with conditional nonce consumption
def update_item(item_id, new_value, client_nonce):
ddb = boto3.client('dynamodb')
try:
ddb.update_item(
TableName='Items',
Key={'id': {'S': item_id}},
UpdateExpression='SET #val = :val',
ConditionExpression='nonce = :nonce',
ExpressionAttributeNames={'#val': 'value'},
ExpressionAttributeValues={
':val': {'S': new_value},
':nonce': {'S': client_nonce}
},
ReturnValues='ALL_NEW'
)
# Nonce is removed from the item by a separate atomic operation
ddb.update_item(
TableName='Items',
Key={'id': {'S': item_id}},
UpdateExpression='REMOVE nonce'
)
except ddb.exceptions.ConditionalCheckFailedException:
raise InvalidRequestError('Invalid or replayed nonce')Alternatively, use DynamoDB's transactional writes (TransactWriteItems) to check and consume the nonce in a single atomic operation.
3. Atomic Counters with Server-Side Validation
For increment operations, store the last request timestamp in a separate attribute and require monotonically increasing timestamps:
// Prevent replay of ADD operations
const params = {
TableName: 'Inventory',
Key: { productId: req.params.id },
UpdateExpression: 'ADD quantity :inc SET lastRequest = :now',
ConditionExpression: 'attribute_not_exists(lastRequest) OR :now > lastRequest',
ExpressionAttributeValues: {
':inc': 1,
':now': Date.now()
}
};
await ddb.updateItem(params).promise();4. Enable DynamoDB Streams with Lambda for Anomaly Detection
Use Streams to trigger a Lambda function that detects duplicate UpdateItem requests within a short window (e.g., same clientRequestToken). This is an advanced pattern but requires additional infrastructure.
Always map fixes to compliance frameworks: OWASP API Top 10 (API5:2023), PCI-DSS requirement 8.2 (session timeout), and SOC2 (logical access controls). middleBrick's Pro plan includes compliance reports that reference these controls.
FAQ
Q: Does DynamoDB have built-in replay protection for pagination tokens?
A: No. DynamoDB returns raw LastEvaluatedKey structures. The application layer must implement token signing or encryption to prevent replay. middleBrick's scanner specifically tests whether tokens are accepted across different user sessions.
Q: Can I use DynamoDB Streams alone to prevent replay attacks?
A: Streams enable detection but not prevention. You would need a Lambda consumer to reject duplicate operations in real-time, which adds latency. Prevention is better handled at the API layer with signed tokens or nonces, as shown in the remediation examples.