Sql Injection in Express with Dynamodb
Sql Injection in Express with Dynamodb — how this specific combination creates or exposes the vulnerability
SQL Injection is commonly associated with relational databases, but injection-style attacks can also manifest against NoSQL stores such as Amazon DynamoDB when user input is used to construct low-level API requests or query expressions. In an Express application that uses the AWS SDK for JavaScript to interact with DynamoDB, the risk arises when request parameters like TableName, key condition expressions, or filter values are directly concatenated from client-controlled data without validation or parameterization.
For example, consider an endpoint that retrieves a user by user_id from query parameters and uses it verbatim in a GetItem request. If the input is not validated, an attacker can attempt to inject additional condition syntax or manipulate the key schema expectations, potentially accessing other items or causing malformed requests that expose sensitive data or error details. DynamoDB’s expression syntax supports placeholders for attribute names and values, but if an application builds expression strings by string interpolation rather than using the built-in expression parameterization, the boundary between data and command blurs.
Another scenario involves scan or query operations where the filter expression is dynamically assembled. If an attacker can influence attribute names or operators through payloads such as username=$or:[{...}], they may try to change logical evaluation to bypass intended filters. While DynamoDB does not execute arbitrary code like SQL, these injection-like manipulations can lead to unauthorized data access, information leakage through error messages, or inefficient queries that contribute to denial-of-service conditions. Because DynamoDB errors can reveal details about table structure or index definitions, improper error handling in Express routes can further aid an attacker in refining injection attempts.
It is important to note that DynamoDB does not support traditional SQL parsing, so classic SQL injection mechanisms do not apply. However, the broader class of injection—where untrusted input influences API request construction—still applies. In Express, this often results from insecure use of the AWS SDK, missing input validation, and overly permissive route definitions. The combination of a flexible NoSQL API and dynamic string assembly creates a surface where injection-style vulnerabilities can exist, and these will be detected by black-box scanning as unexpected data exposure or authorization anomalies.
Dynamodb-Specific Remediation in Express — concrete code fixes
Defending against injection-style issues with DynamoDB in Express centers on strict input validation, use of the SDK’s built-in expression parameterization, and avoiding concatenation of user input into request structures. Below are concrete, safe patterns using the AWS SDK for JavaScript (v3).
1. Use ExpressionParameterizer for Query/Scan
Always use ExpressionAttributeNames and ExpressionAttributeValues instead of injecting user input into key or filter expressions. This ensures that attribute names and values are properly escaped by the SDK and sent as separate parameters to the service.
const { DynamoDBClient, QueryCommand } = require("@aws-sdk/client-dynamodb");
const client = new DynamoDBClient({ region: "us-east-1" });
app.get("/users", async (req, res) => {
const { indexName, email } = req.query;
// Validate allowed index names to prevent injection via ExpressionAttributeNames
const allowedIndexes = ["email-index"];
if (!allowedIndexes.includes(indexName)) {
return res.status(400).json({ error: "Invalid index" });
}
const command = new QueryCommand({
TableName: "Users",
IndexName: indexName,
KeyConditionExpression: "#email = :emailVal",
ExpressionAttributeNames: {
"#email": email, // safe placeholder mapping
},
ExpressionAttributeValues: {
":emailVal": { S: email },
},
});
try {
const response = await client.send(command);
res.json(response.Items);
} catch (err) {
res.status(500).json({ error: "Query failed" });
}
});
2. Validate and Restrict Table Names
Never use raw user input for TableName. Either use a fixed table name or validate against a strict allowlist. This prevents accidental access to unintended tables and reduces injection surface.
app.get("/data/:tableId", async (req, res) => {
const tableId = req.params.tableId;
const allowedTables = { "profile": "UserProfiles", "settings": "AppSettings" };
const tableName = allowedTables[tableId];
if (!tableName) {
return res.status(400).json({ error: "Invalid table" });
}
const command = new GetItemCommand({
TableName: tableName,
Key: {
id: { S: req.query.id },
},
});
const response = await client.send(command);
res.json(response.Item || {});
});
3. Avoid Dynamic Filter Expression Assembly
Do not construct filter or condition expressions by concatenating strings. If dynamic filtering is required, map user inputs to predefined safe expressions or use condition objects that the SDK serializes safely.
app.get("/search", async (req, res) => {
const { status } = req.query;
const statusMap = {
active: "Enabled",
inactive: "Disabled",
};
const statusValue = statusMap[status];
if (!statusValue) {
return res.status(400).json({ error: "Invalid status filter" });
}
const command = new ScanCommand({
TableName: "Tasks",
FilterExpression: "#status = :statusVal",
ExpressionAttributeNames: {
"#status": "status",
},
ExpressionAttributeValues: {
":statusVal": { S: statusValue },
},
});
const response = await client.send(command);
res.json(response.Items);
});
In summary, the primary remediation for DynamoDB in Express is to treat all client input as untrusted when constructing requests, leverage the SDK’s expression parameterization, enforce strict allowlists for names like table and index identifiers, and standardize error handling to avoid leaking metadata. These practices reduce the likelihood of injection-style issues and align with secure-by-default API design.
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 |