HIGH injection flawssailsdynamodb

Injection Flaws in Sails with Dynamodb

Injection Flaws in Sails with Dynamodb — how this specific combination creates or exposes the vulnerability

Injection flaws in a Sails application using DynamoDB typically arise when untrusted input is used to construct low-level database requests. Unlike SQL, DynamoDB does not have a traditional query language, but it does support condition expressions, filter expressions, and key-condition expressions that can be misused if values are concatenated into strings or passed without validation. In Sails, models are often abstracted through Waterline, which provides an ORM-like interface. When developers bypass Waterline’s protections or use native DynamoDB SDK calls directly, they may inadvertently build expressions from user-controlled data.

For example, a dynamic attribute name or a condition expression built by string interpolation can lead to logical injection, where an attacker influences which items are read or which conditions are evaluated. Consider a search endpoint that constructs a KeyConditionExpression from query parameters: partitionKey = :pk AND begins_with(sortKey, :sk). If the sort key prefix is taken directly from user input without sanitization, an attacker can inject additional clauses or change the scan behavior. This maps to the OWASP API Top 10 category “10:2019 – Injection” and can lead to information disclosure or unauthorized data access.

Another common pattern is the use of ExpressionAttributeNames and ExpressionAttributeValues. If attribute names are derived from user input, an attacker may manipulate the structure of the request to access unintended attributes. In the context of BOLA/IDOR, this can allow horizontal privilege escalation where one user modifies the key to access another user’s item. The DynamoDB API does not inherently validate semantic intent; it executes what is given. Therefore, any input that influences expression syntax, key selection, or filter logic must be strictly controlled.

Real-world attack patterns include attempts to bypass logical checks by injecting OR-like semantics through careful nesting of conditions, or exploiting reserved words as attribute names. For instance, supplying __typename or SOMEATTRIBUTE = :val OR begins_with(OTHER, :val) as part of a malformed expression can change the result set. While DynamoDB does not support arbitrary code execution, these logical injections can still result in sensitive data exposure, aligning with the LLM/AI Security checks that detect system prompt leakage or unsafe consumption patterns when models interact with such endpoints.

Middleware in Sails that directly invokes the AWS SDK without input sanitization increases risk. For example, using request parameters to build a Scan or Query without whitelisting allowed filter values exposes the unauthenticated attack surface. middleBrick’s 12 security checks, including Input Validation and Property Authorization, are designed to detect such issues by correlating OpenAPI specifications with runtime behavior, ensuring that expressions are not derived from untrusted sources.

Dynamodb-Specific Remediation in Sails — concrete code fixes

Remediation focuses on strict validation, use of parameterized expressions, and avoiding direct concatenation of user input into DynamoDB expressions. Always prefer Waterline’s query interface when possible, as it provides a layer of abstraction that reduces injection surface. When using the native AWS SDK, construct expressions programmatically using placeholders and bind values through ExpressionAttributeValues.

Below is a secure pattern for querying a DynamoDB table in a Sails controller. This example uses parameterized expressions and validates input against an allowlist before constructing the key condition.

const AWS = require('aws-sdk');
const dynamo = new AWS.DynamoDB.DocumentClient();

module.exports = {
  searchItems: async function (req, res) {
    const { partitionKey, sortKeyPrefix } = req.allParams();

    // Validate input: ensure partitionKey is alphanumeric and sortKeyPrefix has a safe length
    if (!/^[a-zA-Z0-9_-]{1,100}$/.test(partitionKey)) {
      return res.badRequest('Invalid partition key');
    }
    if (!/^[a-zA-Z0-9_\-\.]{1,50}$/.test(sortKeyPrefix)) {
      return res.badRequest('Invalid sort key prefix');
    }

    const params = {
      TableName: 'ItemsTable',
      KeyConditionExpression: '#pk = :pk AND begins_with(#sk, :sk)',
      ExpressionAttributeNames: {
        '#pk': 'partitionKey',
        '#sk': 'sortKey'
      },
      ExpressionAttributeValues: {
        ':pk': partitionKey,
        ':sk': sortKeyPrefix
      },
      Limit: 20
    };

    try {
      const data = await dynamo.query(params).promise();
      return res.ok(data.Items);
    } catch (err) {
      sails.log.error('DynamoDB query error:', err);
      return res.serverError('Unable to fetch items');
    }
  }
};

For more complex filtering, use a whitelist of allowed attribute names and avoid dynamic attribute name construction. If dynamic attributes are necessary, map user-friendly keys to predefined safe names:

const ALLOWED_FILTERS = new Set(['name', 'status', 'createdAt']);

function buildFilterExpression(filters) {
  let expression = '';
  const attributeNames = {};
  const attributeValues = {};
  let index = 0;

  filters.forEach((filter) => {
    if (!ALLOWED_FILTERS.has(filter.attribute)) return;
    const attrName = `#attr${index}`;
    const valName = `:val${index}`;
    expression += `${attrName} = ${valName} AND `;
    attributeNames[attrName] = filter.attribute;
    attributeValues[valName] = filter.value;
    index += 1;
  });

  expression = expression.slice(0, -5); // remove trailing ' AND '
  return {
    FilterExpression: expression,
    ExpressionAttributeNames: attributeNames,
    ExpressionAttributeValues: attributeValues
  };
}

Additionally, apply rate limiting and monitoring on endpoints that interact with DynamoDB to mitigate abuse. middleBrick’s Pro plan supports continuous monitoring and CI/CD integration, which can automatically flag configurations that allow overly broad key expressions. Regularly review scan reports to ensure that Input Validation and Property Authorization checks remain aligned with your data model.

Frequently Asked Questions

How can injection via ExpressionAttributeNames be prevented in Sails with DynamoDB?
Never construct ExpressionAttributeNames from user input. Use a predefined mapping or an allowlist of safe attribute names, and reference them through placeholder tokens in your expressions.
Does middleBrick detect injection risks in DynamoDB expressions?
Yes, middleBrick’s Input Validation and Property Authorization checks analyze runtime behavior against OpenAPI specs to identify cases where user-controlled data may influence DynamoDB expression syntax.