Information Disclosure in Adonisjs with Dynamodb
Information Disclosure in Adonisjs with Dynamodb — how this specific combination creates or exposes the vulnerability
AdonisJS, a Node.js web framework, encourages structured request handling and model-based interactions. When integrating with Amazon DynamoDB, information disclosure risks arise from how data is retrieved, serialized, and exposed through API endpoints. A common pattern is defining a model that maps to a DynamoDB table and returning query results directly in HTTP responses.
Consider an endpoint that fetches a user record by ID using DynamoDB DocumentClient. If the implementation does not explicitly control which attributes are returned, internal fields such as password hashes, secret keys, or metadata may be serialized into the JSON response. DynamoDB stores data as attribute-value pairs; without fine-grained projection expressions, an application can inadvertently return sensitive attributes that were intended for server-side use only.
Additionally, error handling in AdonisJS can contribute to information leakage. Detailed DynamoDB error objects, including system messages or validation details, might be forwarded to the client. For example, a conditional check failure or a provisioned throughput error can reveal table names or indexing strategies when stack traces are enabled in development or misconfigured production environments.
Another vector involves dynamic query construction. If route parameters or query strings are used to build KeyConditionExpression or FilterExpression without strict validation, an attacker may manipulate input to probe schema attributes. While DynamoDB does not return stack traces in normal operation, malformed requests or unauthorized attempts to access non-existent attributes can expose differences in behavior that hint at internal data structures.
Middleware that logs requests or errors can also retain sensitive payload fragments. When AdonisJS hooks or listeners serialize request bodies for debugging, DynamoDB attribute values such as session tokens or personal identifiers might be written to logs, creating a secondary disclosure channel.
These risks align with the OWASP API Top 10 category 'Broken Object Level Authorization' and can intersect with broader compliance frameworks. The combination of an expressive ORM-like layer and a schemaless NoSQL store requires deliberate design to ensure only intended data surfaces to the client.
Dynamodb-Specific Remediation in Adonisjs — concrete code fixes
To mitigate information disclosure, implement explicit attribute selection and strict error handling when using DynamoDB with AdonisJS. Below are concrete, syntactically correct examples demonstrating secure patterns.
1. Controlled Attribute Projection with DocumentClient
Use the ProjectionExpression parameter to return only required attributes. This prevents sensitive fields from being included in the response.
import { DateTime } from 'luxon'
import { BaseModel } from '@ioc:Adonis/Lucid/Orm'
import { DynamoDBDocumentClient, GetCommand } from '@aws-sdk/lib-dynamodb'
import dynamodb from 'path/to/dynamodb_client'
export default class User extends BaseModel {
public static async getUserById(userId: string) {
const command = new GetCommand({
TableName: 'users',
Key: { id: userId },
// Explicitly limit returned attributes
ProjectionExpression: 'id, email, createdAt, updatedAt',
})
const result = await dynamodb.send(command)
return result.Item
}
}
2. Safe Response Serialization
After retrieving the item, construct a clean transfer object instead of forwarding the raw DynamoDB response, which may contain metadata like awsIndexId or internal flags.
import { User } from 'App/Models/User'
export async function showUser({ params, response }) {
const user = await User.getUserById(params.id)
if (!user) {
return response.status(404).json({ error: 'Not found' })
}
// Return only intended fields
return response.json({
id: user.id,
email: user.email,
profile: {
displayName: user.displayName,
avatarUrl: user.avatarUrl,
},
})
}
3. Generic Error Handling without Leaks
Avoid exposing DynamoDB-specific error details. Use a centralized error handler that maps errors to generic messages while logging full details securely.
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import logger from 'App/Logger'
export async function errorHandler({ error, response }: HttpContextContract) {
// Log full error internally
logger.error('Request failed', { error: error.message, stack: error.stack })
// Respond with generic messages
if (error.name === 'ConditionalCheckFailedException') {
return response.status(400).json({ error: 'Bad request' })
}
if (error.name === 'ProvisionedThroughputExceededException') {
return response.status(429).json({ error: 'Too many requests' })
}
response.status(500).json({ error: 'Internal server error' })
}
4. Validate and Sanitize Input for Query Expressions
Ensure that user-controlled values used in expression parameters are validated and do not influence structure in unsafe ways. Use allowlists for field names.
import { schema, rules } from '@ioc:Adonis/Core/Validator'
const userQuerySchema = schema.create({
userId: schema.string({ trim: true, escape: true }),
sortBy: schema.optional.string({}, [
rules.in(['id', 'email', 'createdAt']),
]),
})
export async function listUsers({ request, response }) {
const validated = await request.validate({ schema: userQuerySchema })
const command = new GetCommand({
TableName: 'users',
Key: { id: validated.userId },
// Safe: sortBy is restricted to known attributes
ProjectionExpression: `${validated.sortBy ?? 'id'}, email`,
})
const { Items } = await dynamodb.send(command)
return response.json(Items)
}
5. Disable Debug and Detailed Errors in Production
Ensure environment configuration does not expose stack traces or internal paths. In AdonisJS, this is managed via environment variables consumed by the application configuration.
# .env.production
NODE_ENV=production
DEBUG=false