Formula Injection in Feathersjs with Dynamodb
Formula Injection in Feathersjs with Dynamodb — how this specific combination creates or exposes the vulnerability
Formula Injection occurs when untrusted input is concatenated into expressions that are later evaluated by a backend service. With Feathersjs and Amazon DynamoDB, this typically manifests when user-controlled data is used to construct key expressions, filter objects, or parameterize queries that are passed to DynamoDB operations without proper validation or escaping. Feathersjs services are often configured with a feathers-dynamodb adapter that maps service queries to DynamoDB API calls. If the adapter or service layer interpolates user input into expression strings (for example, building a KeyConditionExpression or FilterExpression using string concatenation or template literals), an attacker can inject additional clauses or operators that alter query semantics.
Consider a search endpoint that accepts a userId and a sortKey from the client. If the implementation builds a DynamoDB query like this:
const baseKey = `userId = :uid AND sortKey = :sk`;
const expression = `${baseKey} AND begins_with(sortKey, :prefix)`;
const params = {
':uid': event.userId,
':sk': event.sortKey,
':prefix': event.prefix
};
const result = await dynamodb.query({ TableName, KeyConditionExpression: expression, ExpressionAttributeValues: params }).promise();
An attacker supplying sortKey as x OR begins_with(sortKey, :prefix) can manipulate the logical structure of the expression. Even with ExpressionAttributeValues used for some parts, the injected clause may change which items are returned or bypass intended partition key equality checks. In DynamoDB, a malformed KeyConditionExpression can cause the service to evaluate unintended access patterns, potentially exposing items belonging to other users (a BOLA/IDOR vector) or enabling data exfiltration through selective filtering.
Another scenario involves filter expressions used after a query. If a Feathersjs service constructs a FilterExpression by concatenating user input, an attacker can inject functions or logical operators that change the result set. For example, an input like 1=1; DELETE FROM table is not a DynamoDB SQL syntax, but injection in the expression layer can still cause excessive data retrieval or condition bypass. Because DynamoDB charges and scales based on read capacity, injected expressions that remove filters can increase provisioned throughput consumption or cause scans to return larger datasets than intended.
Feathersjs middleware that transforms query parameters into DynamoDB expressions must treat all external input as untrusted. Without strict schema validation and whitelisting of allowed fields, operators, and partition key values, the service becomes susceptible to Formula Injection. Attack patterns such as OWASP API Top 10:2023 A1 (Broken Object Level Authorization) and A9 (Injection) are relevant when these expressions are improperly composed. The combination of Feathersjs’s flexible service abstraction and DynamoDB’s expression-based query language requires disciplined input handling to prevent logic manipulation.
Dynamodb-Specific Remediation in Feathersjs — concrete code fixes
Remediation focuses on avoiding expression concatenation with untrusted data, using parameterized expressions exclusively, and validating field-level permissions. In Feathersjs with DynamoDB, prefer the ExpressionAttributeNames and ExpressionAttributeValues mechanisms and never interpolate user input into key condition or filter expression strings.
Instead of building expressions via string templates, construct them with explicit placeholders and map user input only to attribute values. For example:
// Unsafe: concatenating user input into the expression
// const expression = `userId = :uid AND sortKey = :sk AND begins_with(sortKey, :prefix)`;
// Safe: use static expression with placeholders and ExpressionAttributeNames for dynamic field names
const expression = '#uid = :uid AND #sk = :sk';
const names = {
'#uid': 'userId',
'#sk': 'sortKey'
};
const expressionAttributeValues = {
':uid': event.userId,
':sk': event.sortKey
};
const params = {
TableName,
KeyConditionExpression: expression,
ExpressionAttributeNames: names,
ExpressionAttributeValues: expressionAttributeValues
};
const result = await dynamodb.query(params).promise();
If you need dynamic field names (e.g., sorting by different attributes), maintain a strict allowlist:
const ALLOWED_SORT_FIELDS = ['timestamp', 'name', 'createdAt'];
let sortKey = event.sortKey;
if (!ALLOWED_SORT_FIELDS.includes(sortKey)) {
throw new Error('Invalid sort field');
}
const expression = '#uid = :uid AND #sk = :sk';
const names = {
'#uid': 'userId',
'#sk': sortKey // safe because validated against allowlist
};
const params = {
TableName,
KeyConditionExpression: expression,
ExpressionAttributeNames: names,
ExpressionAttributeValues: {
':uid': event.userId,
':sk': event.sortKey
}
};
For filter expressions, avoid concatenating user input. Use ExpressionAttributeValues for all dynamic values and validate operator choices:
const ALLOWED_OPERATORS = ['=', '<>', '<', '<=', '>', '>=', 'begins_with'];
let op = event.operator;
if (!ALLOWED_OPERATORS.includes(op)) {
op = '='; // safe default
}
const filterExpression = `#sk ${op} :val`;
const params = {
TableName,
FilterExpression: filterExpression,
ExpressionAttributeNames: { '#sk': 'sortKey' },
ExpressionAttributeValues: { ':val': event.value }
};
const scanned = await dynamodb.scan(params).promise();
Additionally, enforce field-level permissions in Feathersjs hooks to ensure users can only access their own data regardless of injection attempts:
app.service('items').hooks({
before: {
find: [context => {
// Ensure the query is scoped to the authenticated user
context.params.query.userId = context.params.user.sub;
return context;
}]
}
});
Combine these practices with runtime scanning tools like middleBrick to detect formula injection patterns in your API definitions and runtime behavior. The CLI can be run with middlebrick scan <url> to identify risky expressions and receive prioritized remediation guidance. For teams integrating security into development workflows, the GitHub Action can add API security checks to your CI/CD pipeline, failing builds if risk scores drop below your defined threshold.