Bola Idor in Adonisjs with Dynamodb
Bola Idor in Adonisjs with Dynamodb — how this specific combination creates or exposes the vulnerability
BOLA (Broken Object Level Authorization) / IDOR occurs when an API exposes direct object references and fails to enforce that the authenticated subject is authorized to access the specific resource. In AdonisJS, this commonly arises when route parameters (e.g., :id) are used to look up database records without confirming ownership or tenant context. When the persistence layer is Amazon DynamoDB and the application uses the raw record key (e.g., a PK/SK or a simple numeric ID) without validating access, an attacker can manipulate the identifier to access another user’s data.
With DynamoDB, IDs are often opaque strings or composite keys (partition/sort). If an endpoint accepts a userId or a recordId as a path or query parameter and directly queries DynamoDB using that value—e.g., get({ Key: { id: userId } })—without ensuring the requesting user’s identity matches, the endpoint is vulnerable. For example, an endpoint like GET /api/users/:userId/profile that fetches a profile by userId from DynamoDB and returns it without verifying that the authenticated actor’s ID equals userId allows horizontal IDOR: one user can request another user’s profile simply by changing the numeric path segment.
AdonisJS does not enforce authorization at the model layer by default; it’s the developer’s responsibility to scope queries. With DynamoDB, this means explicitly including the subject’s identifier in the query key condition. A typical mistake is to use a Global Secondary Index (GSI) or primary key lookup that does not incorporate the user or tenant context, enabling an attacker to iterate through valid IDs (IDOR enumeration) or access administrative resources (privilege escalation). For instance, an endpoint that lists items via a query on a GSI without restricting by owner can expose records belonging to other users.
In DynamoDB, keys are unique; if your access control logic omits the user identifier as part of the key expression, the database will return the requested item regardless of permissions. Consider a table where PK encodes USER#{userId} and SK encodes PROFILE#self. A request that supplies a different userId but uses the same static SK can traverse horizontally across users if the backend does not bind the authenticated subject into the key. This becomes more risky when using sparse GSIs that index permissions or roles without enforcing ownership in the query key.
Additionally, unauthenticated LLM endpoints (if exposed) can inadvertently reveal system prompts or internal route naming that hints at DynamoDB key structures, aiding an attacker in crafting IDOR probes. Even in black-box scanning, patterns like predictable numeric IDs or weakly namespaced keys make IDOR likely. Proper scoping—embedding the actor’s ID or tenant ID into the DynamoDB key expression and verifying it on every request—is essential to prevent BOLA/IDOR in this stack.
Dynamodb-Specific Remediation in Adonisjs — concrete code fixes
To remediate BOLA/IDOR in AdonisJS with DynamoDB, ensure every data access includes the authenticated subject’s identifier as part of the key expression. Never trust route or query parameters alone. Use middleware to resolve the actor’s identity and bind it into the query key, and prefer parameterized queries that incorporate the subject ID.
Example: a profile endpoint that safely fetches a user’s own profile by embedding the authenticated user ID into the DynamoDB key. This assumes you have an authenticated session or token that provides userId.
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { DynamoDBClient, GetCommand } from '@aws-sdk/client-dynamodb'
import { marshall, unmarshall } from '@aws-sdk/util-dynamodb'
export default class ProfilesController {
public async show({ auth, params }: HttpContextContract) {
const userId = auth.user?.id
const targetUserId = params.userId
// Enforce authorization: ensure the actor is the resource owner
if (userId !== targetUserId) {
throw new Error('Unauthorized: subject mismatch')
}
const client = new DynamoDBClient({ region: 'us-east-1' })
const command = new GetCommand({
TableName: process.env.DYNAMO_TABLE,
Key: marshall({
PK: `USER#${userId}`, // partition key includes subject
SK: 'PROFILE#self' // sort key for profile
})
})
const { Item } = await client.send(command)
return Item ? unmarshall(Item) : null
}
}
For list or query endpoints, include the subject ID in the index and key condition. For example, if you use a GSI named GSI_OWNER with ownerId as the partition key:
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { DynamoDBClient, QueryCommand } from '@aws-sdk/client-dynamodb'
import { marshall, unmarshall } from '@aws-sdk/util-dynamodb'
export default class ItemsController {
public async index({ auth }: HttpContextContract) {
const userId = auth.user?.id
const client = new DynamoDBClient({ region: 'us-east-1' })
const command = new QueryCommand({
TableName: process.env.DYNAMO_TABLE,
IndexName: 'GSI_OWNER',
KeyConditionExpression: 'ownerId = :uid',
ExpressionAttributeValues: marshall({ ':uid': userId })
})
const { Items } = await client.send(command)
return Items ? Items.map(unmarshall) : []
}
}
Avoid accepting an object ID directly from the client without scoping. If you must expose a resource ID, encode the subject into the ID (e.g., USER#123:PROFILE#self) and validate that the authenticated user’s prefix matches. This prevents horizontal IDOR across users and aligns with least-privilege access patterns in DynamoDB.
Finally, audit your routes and query patterns to ensure no endpoint uses a raw ID without ownership checks. Combine this with middleware that resolves the actor once and passes the subject ID into service/repository layers. This approach reduces the attack surface and mitigates BOLA/IDOR in the AdonisJS + DynamoDB stack.
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 |