Header Injection in Dynamodb
How Header Injection Manifests in Dynamodb
Header injection in DynamoDB contexts typically occurs when HTTP headers are improperly validated and then used to construct database queries or control access to DynamoDB resources. This vulnerability is particularly dangerous in serverless architectures where API Gateway directly integrates with Lambda functions that interact with DynamoDB.
A common pattern involves using headers to control table names, partition keys, or filter expressions. For example:
const tableName = event.headers['x-table-name'];
const userId = event.headers['x-user-id'];
const params = {
TableName: tableName,
Key: {
'user_id': userId
}
};
const result = await dynamodb.get(params).promise();This code is vulnerable because an attacker can set the x-table-name header to any value, potentially accessing tables they shouldn't have permissions for. More sophisticated attacks might use headers to inject into DynamoDB expressions:
const filter = event.headers['x-filter'];
const params = {
TableName: 'users',
FilterExpression: filter
};
const result = await dynamodb.scan(params).promise();An attacker could set x-filter to username = 'admin' AND attribute_exists(password), extracting sensitive data. DynamoDB's PartiQL injection is another variant where headers control query construction:
const userId = event.headers['x-user-id'];
const query = `SELECT * FROM users WHERE user_id = '${userId}'`;
const result = await dynamodb.executeStatement({
Statement: query
}).promise();Without proper validation, x-user-id could contain SQL-like syntax that alters the query's intent.
Dynamodb-Specific Detection
Detecting header injection in DynamoDB applications requires examining both the API layer and the database interaction patterns. middleBrick's scanner specifically tests for these vulnerabilities by sending crafted headers and analyzing responses.
Key detection patterns include:
- Table name injection: Testing if arbitrary table names in headers return data
- Expression injection: Sending malformed FilterExpression or KeyConditionExpression values
- PartiQL injection: Testing for SQL-like syntax in headers used in executeStatement calls
- Projection manipulation: Checking if headers control which attributes are returned
middleBrick's detection process for DynamoDB-specific header injection:
{
"header_injection": {
"test_cases": [
{
"name": "table_name_injection",
"headers": {"x-table-name": "users; DROP TABLE sensitive_data"},
"expected_behavior": "should reject invalid table names"
},
{
"name": "expression_injection",
"headers": {"x-filter": "username = 'admin' OR 1=1"},
"expected_behavior": "should sanitize filter expressions"
}
],
"severity": "high",
"impact": "unauthorized data access, data exfiltration"
}
}Manual detection should focus on code review patterns. Look for:
// Vulnerable pattern - direct header usage
const tableName = event.headers['x-table'];
// Safer pattern - whitelist validation
const allowedTables = ['users', 'orders', 'products'];
const tableName = event.headers['x-table'];
if (!allowedTables.includes(tableName)) {
throw new Error('Invalid table name');
}Scan your Lambda functions for patterns where headers directly influence DynamoDB parameters without validation. Pay special attention to any code that constructs expressions dynamically based on header values.
Dynamodb-Specific Remediation
Remediating header injection in DynamoDB applications requires a defense-in-depth approach. The most effective strategy combines input validation, least privilege IAM policies, and safe query construction patterns.
Input Validation
Always validate header values against strict patterns before using them in DynamoDB operations:
const validateTableName = (tableName) => {
const validTablePattern = /^[a-zA-Z0-9_-]{3,255}$/;
return validTablePattern.test(tableName);
};
const validateUserId = (userId) => {
const validIdPattern = /^[a-f0-9]{24,36}$/;
return validIdPattern.test(userId);
};
// Usage
const tableName = event.headers['x-table-name'];
if (!validateTableName(tableName)) {
return { statusCode: 400, body: 'Invalid table name' };
}Whitelist Approach
Instead of validating against patterns, use whitelists for known-good values:
const allowedTables = new Set(['users', 'orders', 'products', 'inventory']);
const tableName = event.headers['x-table-name'];
if (!allowedTables.has(tableName)) {
return { statusCode: 400, body: 'Invalid table name' };
}Least Privilege IAM Policies
Restrict DynamoDB access to only what's necessary:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:Query",
"dynamodb:Scan"
],
"Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/users"
}
]
}Safe Query Construction
Avoid dynamic expression construction. Use parameterized expressions:
// Vulnerable
const filter = event.headers['x-filter'];
const params = { TableName: 'users', FilterExpression: filter };
// Safe
const userId = event.headers['x-user-id'];
const params = {
TableName: 'users',
KeyConditionExpression: 'user_id = :userId',
ExpressionAttributeValues: { ':userId': userId }
};middleBrick Integration
After implementing these fixes, use middleBrick to verify remediation:
middlebrick scan https://api.example.com/users \
--headers 'x-table-name: users' \
--headers 'x-user-id: valid-user-id'
# Test for injection attempts
middlebrick scan https://api.example.com/users \
--headers 'x-table-name: malicious_table' \
--headers 'x-filter: username = ''admin'' OR 1=1'The scanner will attempt various injection payloads and verify that your validation logic properly rejects them, providing a security score and detailed findings for each test case.