Pii Leakage in Adonisjs with Dynamodb
Pii Leakage in Adonisjs with Dynamodb — how this specific combination creates or exposes the vulnerability
AdonisJS is a Node.js web framework that encourages structured request handling and model-based interactions. When integrating AdonisJS with Amazon DynamoDB as the persistence layer, PII leakage can occur through several realistic patterns tied to how data is modeled, serialized, and returned from DynamoDB.
DynamoDB stores items as attribute-value maps, which means fields containing sensitive information—such as email, phone, or government identifiers—reside in the same item as operational data. If query or scan responses in AdonisJS controllers directly forward DynamoDB output to clients (e.g., JSON HTTP responses), any PII present in those attributes is exposed. This commonly happens when models or service layers do not explicitly filter or transform sensitive fields before serialization.
Another vector arises from incomplete or misconfigured DynamoDB queries. For example, using a query without a precise key condition may unintentionally return multiple items, increasing the likelihood of exposing more PII than intended. Additionally, DynamoDB supports sparse indexes; if an index omits sensitive attributes but the base table includes them, developers might mistakenly assume the index is safe, whereas runtime reads from the main table can still expose PII when referenced indirectly.
AdonisJS-specific risks include overly broad model definitions that map 1:1 to DynamoDB item structures. Without explicit getters or serialization logic, attributes like user_phone or ssn can appear directly in JSON responses. In a typical API route, code such as return User.query().where('email', email).first() might return the full DynamoDB item, including raw PII fields, to the client.
Furthermore, logging or error handling in AdonisJS that inadvertently includes DynamoDB item contents can expose PII in server logs or error traces, especially when debugging information is enabled in production. Since DynamoDB responses include metadata such as ConsumedCapacity, developers might inadvertently serialize the entire response object rather than the relevant data subset.
To mitigate these risks, treat DynamoDB items as raw data records and enforce strict serialization in AdonisJS. Use model fields or view models to expose only necessary attributes, and avoid passing DynamoDB responses directly to HTTP responses. Apply consistent input validation and output filtering in controller methods to ensure PII is either redacted or transformed before leaving the application layer.
Dynamodb-Specific Remediation in Adonisjs — concrete code fixes
Remediation focuses on controlling what leaves the server and ensuring DynamoDB interactions in AdonisJS never expose PII inadvertently. Below are concrete patterns and code examples tailored for AdonisJS with DynamoDB.
1. Explicit projection and attribute filtering
Use DynamoDB ProjectionExpression to retrieve only required, non-sensitive attributes. In AdonisJS, this means configuring the DynamoDB client call within your model or service to limit returned fields.
const { DynamoDBClient, QueryCommand } = require('@aws-sdk/client-dynamodb');
const client = new DynamoDBClient({ region: 'us-east-1' });
async function getUserPublicFields(email) {
const command = new QueryCommand({
TableName: process.env.USERS_TABLE,
IndexName: 'email-index',
KeyConditionExpression: 'email = :email',
ExpressionAttributeValues: {
':email': { S: email }
},
ProjectionExpression: 'user_id, username, created_at' // excludes email, phone, ssn
});
const response = await client.send(command);
return response.Items;
}
2. Model-level serialization with getters
Define explicit getters in your AdonisJS model to control serialization. This ensures that whenever the model is converted to JSON, sensitive fields are omitted or masked.
const BaseModel = use('Model');
class User extends BaseModel {
static get computed () {
return ['publicProfile'];
}
toJSON() {
const data = this.serialize();
// Remove PII fields before sending
delete data.email;
delete data.phone;
delete data.ssn;
return data;
}
getPublicProfile() {
return {
user_id: this.user_id,
username: this.username,
created_at: this.created_at
};
}
}
module.exports = User;
3. Service layer transformation
Create a service that transforms DynamoDB responses into safe output objects, centralizing the logic and preventing accidental PII exposure across routes.
class UserService {
async getUserById(userId) {
const command = new GetCommand({
TableName: process.env.USERS_TABLE,
Key: { user_id: { S: userId } },
ProjectionExpression: 'user_id, username, settings' // excludes contact info
});
const { Item } = await dynamo.send(command);
// Transform to plain object without PII
return {
user_id: Item.user_id.S,
username: Item.username.S,
settings: JSON.parse(Item.settings.S || '{}')
};
}
}
4. Input validation and least privilege queries
Validate incoming query parameters rigorously and avoid scanning entire tables. Use conditional queries with key expressions to minimize the dataset returned by DynamoDB.
async function getUserByEmail(email) {
if (!isValidEmail(email)) {
throw new Error('Invalid email format');
}
const command = new QueryCommand({
TableName: process.env.USERS_TABLE,
KeyConditionExpression: 'email = :email',
ExpressionAttributeValues: { ':email': { S: email } },
Limit: 1
});
const { Items } = await client.send(command);
return Items ? Items[0] : null;
}
5. Redact logs and error objects
Ensure that logging utilities in AdonisJS do not serialize full DynamoDB items. Use selective logging and scrub sensitive fields explicitly.
const logger = use('Logger');
app.exceptionHandler(async (error, { response }) => {
if (error.name === 'ResourceNotFoundException') {
logger.info('Resource not found', { table: process.env.USERS_TABLE });
return response.status(404).send({ message: 'Not found' });
}
// Avoid logging full error.meta or DynamoDB items
logger.error('Request error', { code: error.code, path: error.path });
response.status(500).send({ error: 'Internal error' });
});
By combining projection, serialization, and service-layer transformation, AdonisJS applications can safely work with DynamoDB while minimizing the risk of PII leakage.
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |