Mass Assignment in Dynamodb
How Mass Assignment Manifests in Dynamodb
Mass assignment vulnerabilities in Dynamodb occur when applications accept untrusted input to populate Dynamodb item attributes without proper validation or filtering. This creates several attack vectors specific to Dynamodb's data model and API.
The most common scenario involves client-side filtering of Dynamodb attributes. When a client requests specific attributes, an attacker can manipulate the request to include sensitive attributes they shouldn't access. For example:
const params = {
TableName: 'Users',
Key: { id: '123' },
AttributesToGet: req.query.attributes.split(',') // Untrusted input!
};
const result = await dynamodb.get(params).promise();An attacker could request id,ssn,credit_card to retrieve sensitive data. Dynamodb will return whatever attributes exist in the item, regardless of the user's authorization level.
Another pattern involves bulk updates where clients specify which attributes to modify. Consider this vulnerable code:
app.patch('/users/:id', async (req, res) => {
const updates = req.body.updates; // { 'email': 'new@example.com', 'isAdmin': true }
const params = {
TableName: 'Users',
Key: { id: req.params.id },
UpdateExpression: 'set ' + Object.keys(updates).map((k, i) => `#${k} = :val${i}`).join(', '),
ExpressionAttributeNames: Object.keys(updates).reduce((acc, k) => ({ ...acc, [`#${k}`]: k }), {}),
ExpressionAttributeValues: Object.keys(updates).reduce((acc, k, i) => ({ ...acc, [`:val${i}`]: updates[k] }), {})
};
await dynamodb.update(params).promise();
});Here, an authenticated user could escalate privileges by setting isAdmin to true, or modify any attribute they shouldn't control.
Dynamodb's lack of built-in row-level security makes this particularly dangerous. Unlike SQL databases with views or stored procedures, Dynamodb applies operations directly to items. If a user can craft a valid Dynamodb request, the operation executes without additional authorization checks.
Batch operations amplify the risk. BatchWriteItem and BatchGetItem accept arrays of requests, allowing attackers to enumerate multiple items or modify several records in a single operation:
const batchParams = {
RequestItems: {
'Users': [
{ PutRequest: { Item: { id: 'hacker', isAdmin: true, email: 'hacker@example.com' } } },
{ PutRequest: { Item: { id: 'victim', email: 'hacked@example.com' } } }
]
}
};
await dynamodb.batchWrite(batchParams).promise();The TransactWriteItems operation poses similar risks, allowing conditional updates across multiple items that could bypass application-level authorization if not properly validated.
Dynamodb-Specific Detection
Detecting mass assignment vulnerabilities in Dynamodb requires examining both code patterns and runtime behavior. Code analysis should focus on these specific indicators:
Untrusted Attribute Lists
const attributes = req.query.attributes?.split(',') || ['id', 'name'];
const params = {
TableName: 'Users',
Key: { id: userId },
AttributesToGet: attributes // Vulnerable if attributes are user-controlled
};Direct Client Updates
const updates = req.body;
const updateExpr = 'set ' + Object.keys(updates).map(k => `${k} = :${k}`).join(', ');
const values = Object.keys(updates).reduce((acc, k) => ({ ...acc, [`:${k}`]: updates[k] }), {});
const params = {
TableName: 'Users',
Key: { id: userId },
UpdateExpression: updateExpr,
ExpressionAttributeValues: values
};Batch Operations with User Input
const batchRequests = req.body.requests.map(r => ({
PutRequest: { Item: r.item }
}));
const params = {
RequestItems: { [tableName]: batchRequests }
};Runtime detection with middleBrick specifically targets Dynamodb endpoints by sending crafted requests that attempt to access or modify restricted attributes. The scanner tests for:
- Attribute enumeration attacks using
AttributesToGetwith common sensitive field names (ssn, credit_card, password, isAdmin, role) - Update expression manipulation attempting to set restricted attributes
- Batch operations targeting multiple items with varying permissions
- Conditional expression bypasses using
ConditionExpression
middleBrick's Dynamodb-specific checks include scanning for common IAM permission misconfigurations that enable mass assignment, such as overly permissive UpdateItem or PutItem permissions granted to application roles.
The scanner also examines OpenAPI specifications for Dynamodb operations, flagging endpoints that accept arbitrary attribute lists or update objects without validation. This spec analysis helps identify vulnerabilities before deployment.
Dynamodb-Specific Remediation
Remediating mass assignment vulnerabilities in Dynamodb requires a defense-in-depth approach using Dynamodb's native features combined with application-level controls.
Whitelist Attribute Access
Instead of accepting arbitrary attribute lists, explicitly define allowed attributes:
const allowedAttributes = ['id', 'name', 'email', 'createdAt'];
const requested = req.query.attributes?.split(',') || [];
const safeAttributes = requested.filter(attr => allowedAttributes.includes(attr));
const params = {
TableName: 'Users',
Key: { id: userId },
AttributesToGet: safeAttributes.length ? safeAttributes : allowedAttributes
};Attribute-Level Validation
Validate update operations against a schema of permitted fields:
const allowedUpdates = ['email', 'name', 'phone'];
const updates = req.body.updates || {};
const invalidFields = Object.keys(updates).filter(k => !allowedUpdates.includes(k));
if (invalidFields.length > 0) {
return res.status(400).json({ error: 'Invalid fields: ' + invalidFields.join(', ') });
}
const updateExpr = 'set ' + Object.keys(updates).map(k => `${k} = :${k}`).join(', ');
const values = Object.keys(updates).reduce((acc, k) => ({ ...acc, [`:${k}`]: updates[k] }), {});
const params = {
TableName: 'Users',
Key: { id: userId },
UpdateExpression: updateExpr,
ExpressionAttributeValues: values
};Conditional Writes for Authorization
Use Dynamodb's conditional expressions to enforce authorization at the database level:
const params = {
TableName: 'Users',
Key: { id: userId },
UpdateExpression: 'set email = :email',
ExpressionAttributeValues: { ':email': newEmail },
ConditionExpression: 'attribute_exists(id) AND #role = :currentRole',
ExpressionAttributeNames: { '#role': 'role' },
ExpressionAttributeValues: { ...values, ':currentRole': userRole }
};This ensures users can only modify their own records or have appropriate role-based permissions.
Batch Operation Safeguards
Validate batch operations thoroughly:
function validateBatchRequests(requests, userId, userRole) {
return requests.every(req => {
// Check if user owns the item or has admin rights
const isOwner = req.PutRequest.Item.id === userId;
const isAdmin = userRole === 'admin';
if (!isOwner && !isAdmin) return false;
// Validate item attributes
const allowedAttrs = ['id', 'name', 'email'];
const itemAttrs = Object.keys(req.PutRequest.Item);
return itemAttrs.every(attr => allowedAttrs.includes(attr));
});
}IAM Policy Restrictions
Implement least-privilege IAM policies that limit what attributes applications can modify:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:UpdateItem"
],
"Resource": "arn:aws:dynamodb:region:account:table/Users",
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:Attributes": ["id", "name", "email", "phone"]
}
}
}
]
}This policy ensures even if application code is vulnerable, the IAM permissions restrict which attributes can be accessed or modified.
Related CWEs: propertyAuthorization
| CWE ID | Name | Severity |
|---|---|---|
| CWE-915 | Mass Assignment | HIGH |