Sql Injection in Adonisjs with Dynamodb
Sql Injection in Adonisjs with Dynamodb — how this specific combination creates or exposes the vulnerability
SQL Injection (SQLi) classically targets relational databases, but injection concepts translate to NoSQL contexts when query construction is driven by unchecked user input. With AdonisJS and DynamoDB, the risk emerges not from SQL strings but from building PartiQL or condition expressions using raw concatenation or improperly sanitized request data. If your AdonisJS controller passes query parameters directly into DynamoDB condition expressions, you can create injection-like behavior that bypasses intended access controls or extracts unintended data.
In AdonisJS, developers often use the AWS SDK for JavaScript to interact with DynamoDB. When constructing KeyConditionExpression, FilterExpression, or ExpressionAttributeValues from request inputs without parameterization or strict validation, attackers can inject expressions. For example, a user ID taken directly from the query string and concatenated into a KeyConditionExpression can change the partition key scope or enable scanning across partitions. Similarly, dynamic filter strings built from JSON input can introduce logical tautologies like 1=1 or escape intended filtering boundaries.
Even though DynamoDB does not use SQL, injection-like outcomes occur when expression building is error-prone. AdonisJS middleware that does not validate or type-cast input can pass strings like 'userId = \'123\' OR \'1\' = \'1' into a FilterExpression, which may evaluate unexpectedly due to string parsing logic in the application layer. Attackers can also probe for unauthenticated endpoints where DynamoDB queries are constructed, attempting to enumerate data or infer schema via error messages returned by malformed expressions.
The LLM/AI Security checks unique to middleBrick highlight system prompt leakage and prompt injection, but analogous risks in API query construction are mitigated through strict input validation and expression parameterization. DynamoDB’s expression syntax requires disciplined use of ExpressionAttributeNames and ExpressionAttributeValues to avoid accidental injection. Without these safeguards, an API that exposes DynamoDB query parameters to the client surface can leak data or allow privilege escalation, aligning with BOLA/IDOR and Input Validation checks in middleBrick scans.
Dynamodb-Specific Remediation in Adonisjs — concrete code fixes
Remediation centers on never concatenating user input into DynamoDB expressions and always using parameterized expressions with bound values. In AdonisJS, structure your DynamoDB client usage so that query components are derived from controlled sources, not raw request bodies. Use whitelisting for field names and strict type validation for values.
Safe KeyConditionExpression with partition key
Assume a User table where userId is the partition key. Validate and cast the incoming identifier, then use ExpressionAttributeValues:
import { DynamoDB } from 'aws-sdk';
import { schema } from '@ioc:Adonis/Core/Validator';
const getUserOrders = async ({ request, response }) => {
const userSchema = schema.create({
userId: schema.string({}, { trim: true, escape: false }),
});
const payload = await request.validate({ schema: userSchema });
const ddb = new DynamoDB({});
const params = {
TableName: 'Orders',
KeyConditionExpression: 'userId = :uid',
ExpressionAttributeValues: {
':uid': { S: payload.userId },
},
};
const data = await ddb.query(params).promise();
return data.Items || [];
};
Safe FilterExpression with ExpressionAttributeNames for dynamic fields
When filtering on user-supplied field names, map them through a whitelist to prevent injection via attribute names:
const allowedFields = new Set(['status', 'createdAt', 'priority']);
const buildFilter = (field, value) => {
if (!allowedFields.has(field)) {
throw new Error('Invalid filter field');
}
return {
FilterExpression: '#f = :val',
ExpressionAttributeNames: { '#f': field },
ExpressionAttributeValues: { ':val': { S: value } },
};
};
const filterParams = buildFilter('status', 'active');
const scanParams = {
TableName: 'Tasks',
...filterParams,
};
const data = await ddb.scan(scanParams).promise();
Avoiding logical tautologies and type confusion
Ensure numeric or typed values are not treated as strings. Use appropriate DynamoDB type wrappers and avoid string coercion that could change expression semantics:
const buildNumericFilter = (min, max) => {
const minVal = Number(min);
const maxVal = Number(max);
if (Number.isNaN(minVal) || Number.isNaN(maxVal)) {
throw new Error('Invalid numeric range');
}
return {
FilterExpression: 'score BETWEEN :lo AND :hi',
ExpressionAttributeValues: {
':lo': { N: minVal.toString() },
':hi': { N: maxVal.toString() },
},
};
};
Leverage middleBrick’s Input Validation and BOLA/IDOR checks to ensure your endpoints do not expose unsafe expression building. When scanning with the CLI or Web Dashboard, review per-category breakdowns to confirm that expressions remain parameterized and that no unauthenticated endpoints allow raw query assembly.
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |