HIGH mass assignmentfeathersjsdynamodb

Mass Assignment in Feathersjs with Dynamodb

Mass Assignment in Feathersjs with Dynamodb — how this specific combination creates or exposes the vulnerability

Mass assignment occurs when a service accepts user-supplied data and writes it directly to a data source without filtering which fields can be set. In a Feathersjs application using Dynamodb as the persistence layer, this typically happens through a create or patch call that passes an unfiltered payload into a DynamoDB PutItem or UpdateItem request. Feathersjs hooks often forward data straight to the service, and if the service uses a low-level DynamoDB client without a strict schema or field allowlist, an attacker can inject unexpected attributes such as metadata flags, administrative roles, or conditional expression tokens that influence how DynamoDB processes the write.

Because DynamoDB stores schemaless JSON-like documents, unexpected keys are accepted silently. This enables attackers to set reserved or sensitive attributes (e.g., aws:Reserved, custom policy fields, or versioning keys) that the application logic did not intend to be user-writable. If the application later reads those attributes to make authorization or business decisions, the injected values can bypass controls. For example, an attacker could supply { "role": "admin", "shouldImpersonate": true } in a user profile update, and if the hook does not strip or reject these fields, the DynamoDB record will reflect them.

The risk is compounded when combined with other checks in the 12-scan suite, such as Property Authorization and Input Validation. Without an allowlist strategy, the attack surface grows as new fields are added to the client model but not enforced server-side. An OpenAPI spec that does not tightly constrain request properties can further mask the issue, because schema validation may be absent or permissive. This is why runtime findings from tools that compare the spec to actual behavior are important for surfacing unchecked writable properties.

Dynamodb-Specific Remediation in Feathersjs — concrete code fixes

Remediation focuses on explicit field filtering and schema enforcement in Feathersjs hooks before interacting with DynamoDB. Use a whitelist approach to pick only the fields that are safe to update, and validate input types and lengths to reduce injection risk. Below are concrete code examples that demonstrate how to secure both create and patch operations when using the AWS SDK for JavaScript v3 with DynamoDB in a Feathersjs service.

Example: Securing create with a whitelist

const { DynamoDBClient, PutItemCommand } = require('@aws-sdk/client-dynamodb');
const client = new DynamoDBClient({ region: 'us-east-1' });

function safeCreate(data) {
  const ALLOWED = ['name', 'email', 'preferences'];
  const item = {};
  ALLOWED.forEach((key) => {
    if (data[key] !== undefined) {
      // Basic scalar validation can be added here
      item[key] = { S: String(data[key]) };
    }
  });
  return item;
}

app.service('todos').hooks({
  before: {
    create: [context => {
      context.data = safeCreate(context.data);
      return context;
    }]
  }
});

Example: Securing patch with partial updates and expression attribute values

function buildUpdateExpression(allowed, data) {
  const updateParts = [];
  const expressionAttrValues = {};
  const keys = Object.keys(data);
  keys.forEach((key, idx) => {
    if (!allowed.includes(key)) return;
    const placeholder = `#val${idx}`;
    const attrPlaceholder = `:val${idx}`;
    updateParts.push(`${key} = ${placeholder}`);
    expressionAttrValues[placeholder] = { S: String(data[key]) };
    expressionAttrValues[attrPlaceholder] = { S: String(data[key]) };
  });
  return {
    UpdateExpression: 'SET ' + updateParts.join(', '),
    ExpressionAttributeNames: Object.keys(expressionAttrValues).reduce((acc, k) => {
      acc[k] = k; return acc;
    }, {}),
    ExpressionAttributeValues: expressionAttrValues
  };
}

app.service('todos').hooks({
  before: {
    patch: [context => {
      const ALLOWED = ['name', 'email', 'preferences'];
      const update = buildUpdateExpression(ALLOWED, context.data);
      context.params.request = {
        TableName: 'Todos',
        Key: { id: { S: context.id } },
        ...update
      };
      // Replace low-level call with service method or SDK wrapper as appropriate
      return context;
    }]
  }
});

Additional DynamoDB hardening tips

  • Define a JSON schema for your entities and validate payloads before constructing DynamoDB expressions.
  • Use ConditionExpression for critical constraints (e.g., attribute existence) rather than relying solely on application logic.
  • Avoid passing raw user input into ExpressionAttributeNames; map known safe names instead.
  • Combine these hooks with Property Authorization checks to ensure users can only modify fields they are permitted to change.

These steps ensure that even if a client sends extra fields, they are ignored by the DynamoDB write operations, effectively mitigating mass assignment in this stack.

Related CWEs: propertyAuthorization

CWE IDNameSeverity
CWE-915Mass Assignment HIGH

Frequently Asked Questions

Can mass assignment be detected by checking the OpenAPI spec alone?
An OpenAPI spec can highlight missing field constraints, but it cannot guarantee runtime behavior. You should combine spec analysis with runtime scanning that compares actual writes to the declared schema; this helps uncover permissive payload acceptance that a spec alone might miss.
Does using a framework helper automatically protect against mass assignment?
Framework helpers reduce risk only if they enforce a strict allowlist. If the helper is configured to permit all properties or is bypassed by custom hooks, mass assignment can still occur. Always verify which fields are passed to DynamoDB in your service code.