Bola Idor in Hapi with Dynamodb
Bola Idor in Hapi with Dynamodb — how this specific combination creates or exposes the vulnerability
Broken Object Level Authorization (BOLA) occurs when an API exposes object references and fails to enforce that the authenticated context is allowed to access a specific instance. In a Hapi application using Amazon DynamoDB as the persistence layer, the risk arises from coupling an object’s primary key (e.g., a DynamoDB partition/sort key) with an authorization check that is incomplete or deferred. A typical pattern might look like a route like /users/{id} where id is directly used as a DynamoDB key without verifying that the requesting user owns or is permitted to interact with that item.
DynamoDB’s key design encourages storing a single item per entity, often using a composite key such as PK = USER#123 and SK = PROFILE. If a Hapi route accepts an id from the client and uses it to construct a GetItem or Query request without ensuring that the id maps to the requesting user’s scope, an attacker can iterate through plausible keys (e.g., USER#124, USER#125) and read or modify other users’ data. This is a classic BOLA/IDOR scenario: the identifier itself is predictable, and authorization is missing or insufficient.
An additional dimension in Hapi with DynamoDB is the use of DynamoDB expressions for filtering. For example, a developer might retrieve a list of items and then filter in application code instead of pushing the authorization into the query. Consider a route intended to fetch a user’s posts: the query might use a partition key like USER#123 but if the client can supply a different partition key or a sortKey value, and the server does not re-confirm ownership, BOLA emerges. Even when using the AWS SDK within Hapi, failing to scope the request with the authenticated user’s identity (e.g., from a session or token) and instead relying on client-supplied identifiers opens a path for horizontal privilege escalation.
A concrete example would be a Hapi handler that extracts an itemId from the request parameters, builds a DynamoDB GetItem input using that itemId, and retrieves the item without cross-checking that the item’s ownerId attribute matches the authenticated user’s ID. Because DynamoDB returns the item if the key exists regardless of application-level permissions, the server may inadvertently leak private data or allow unauthorized updates. This pattern is commonly flagged by middleBrick’s BOLA/IDOR checks, especially when combined with DynamoDB’s key structure and when route parameters are used directly as keys.
Moreover, if the Hapi route exposes endpoints that mutate state based on user-supplied keys without verifying authorization, the same BOLA issue can lead to unauthorized modification or deletion. For instance, a DELETE or PUT that uses a client-provided DynamoDB key without ensuring that the authenticated principal owns the item can be exploited to tamper with other users’ resources. The risk is amplified when the DynamoDB table is wide (many attributes per item) and the authorization check is performed after data retrieval rather than as part of the key construction or query filter.
Dynamodb-Specific Remediation in Hapi — concrete code fixes
To mitigate BOLA in a Hapi service backed by DynamoDB, always tie data access to the authenticated subject and construct keys server-side rather than accepting them from the client. Instead of using a user-supplied identifier directly as a DynamoDB key, derive the partition key from the authenticated identity and use the client-provided value only as a sort key or attribute within a scoped query.
For example, if you store user data with a composite key where the partition key encodes the user identity, build the key on the server using the authenticated user’s ID. This ensures that even if an attacker manipulates the request, they cannot escape their authorization boundary.
// Hapi handler with DynamoDB scoped by authenticated user ID
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB.DocumentClient();
const handler = async (request, h) => {
// Assume request.auth.credentials.userId is set by your auth strategy
const userId = request.auth.credentials.userId;
const { itemId } = request.params;
const params = {
TableName: process.env.TABLE_NAME,
Key: {
pk: `USER#${userId}`,
sk: `ITEM#${itemId}`
}
};
const result = await dynamodb.get(params).promise();
if (!result.Item) {
return h.response({ error: 'Not found' }).code(404);
}
return result.Item;
};
When querying multiple items (for example, a user’s posts), scope the partition key to the authenticated user and use a filter expression for additional constraints rather than allowing the client to dictate the partition key. This prevents horizontal BOLA across other users’ items.
// Query limited to the authenticated user’s items
const params = {
TableName: process.env.TABLE_NAME,
KeyConditionExpression: 'pk = :pk AND begins_with(sk, :skPrefix)',
ExpressionAttributeValues: {
':pk': `USER#${userId}`,
':skPrefix': 'POST#'
}
};
const result = await dynamodb.query(params).promise();
return result.Items;
In update or delete operations, recompute the key on the server and avoid using client-supplied identifiers directly. If you must accept an identifier, map it to a server-side key and verify ownership before proceeding. This pattern aligns with DynamoDB best practices and reduces the attack surface for BOLA/IDOR.
// Safe update: server-side key derivation and ownership check
const params = {
TableName: process.env.TABLE_NAME,
Key: {
pk: `USER#${userId}`,
sk: `ITEM#${itemId}`
},
UpdateExpression: 'set #status = :status',
ExpressionAttributeNames: { '#status': 'status' },
ExpressionAttributeValues: { ':status': 'archived' }
};
const result = await dynamodb.update(params).promise();
Finally, validate and sanitize any condition expressions or filter rules that include user input. Prefer using ExpressionAttributeValues over interpolating values to avoid injection issues and ensure that your authorization logic is consistently applied before any DynamoDB operation. middleBrick scans can surface these patterns when you test endpoints that expose DynamoDB-backed routes; the Pro plan’s continuous monitoring can help detect regressions as your route definitions evolve.
Related CWEs: bolaAuthorization
| CWE ID | Name | Severity |
|---|---|---|
| CWE-250 | Execution with Unnecessary Privileges | HIGH |
| CWE-639 | Insecure Direct Object Reference | CRITICAL |
| CWE-732 | Incorrect Permission Assignment | HIGH |