javascript.aws-lambda.security.dynamodb-request-object.dynamodb-request-object

profile photo of returntocorpreturntocorp
Author
unknown
Download Count*

Detected DynamoDB query params that are tainted by $EVENT object. This could lead to NoSQL injection if the variable is user-controlled and not properly sanitized. Explicitly assign query params instead of passing data from $EVENT directly to DynamoDB client.

Run Locally

Run in CI

Defintion

rules:
  - id: dynamodb-request-object
    message: Detected DynamoDB query params that are tainted by `$EVENT` object.
      This could lead to NoSQL injection if the variable is user-controlled and
      not properly sanitized. Explicitly assign query params instead of passing
      data from `$EVENT` directly to DynamoDB client.
    metadata:
      cwe:
        - "CWE-943: Improper Neutralization of Special Elements in Data Query
          Logic"
      owasp:
        - A01:2017 - Injection
      category: security
      technology:
        - javascript
        - aws-lambda
        - dynamodb
      subcategory:
        - vuln
      likelihood: MEDIUM
      impact: HIGH
      confidence: MEDIUM
      references:
        - https://owasp.org/Top10/A03_2021-Injection
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
    languages:
      - javascript
      - typescript
    severity: ERROR
    mode: taint
    pattern-sources:
      - patterns:
          - pattern: $EVENT
          - pattern-either:
              - pattern-inside: |
                  exports.handler = function ($EVENT, ...) {
                    ...
                  }
              - pattern-inside: |
                  function $FUNC ($EVENT, ...) {...}
                  ...
                  exports.handler = $FUNC
              - pattern-inside: |
                  $FUNC = function ($EVENT, ...) {...}
                  ...
                  exports.handler = $FUNC
    pattern-sinks:
      - patterns:
          - pattern: $SINK
          - pattern-inside: |
              $DC.$METHOD($SINK, ...)
          - metavariable-regex:
              metavariable: $METHOD
              regex: (query|send|scan|delete|put|transactWrite|update|batchExecuteStatement|executeStatement|executeTransaction|transactWriteItems)
          - pattern-either:
              - pattern-inside: |
                  $DC = new $AWS.DocumentClient(...);
                  ...
              - pattern-inside: |
                  $DC = new $AWS.DynamoDB(...);
                  ...
              - pattern-inside: |
                  $DC = new DynamoDBClient(...);
                  ...
              - pattern-inside: |
                  $DC = DynamoDBDocumentClient.from(...);
                  ...
    pattern-sanitizers:
      - patterns:
          - pattern: |
              {...}

Examples

dynamodb-request-object.js

const AWS = require('aws-sdk')

var documentClient = new AWS.DynamoDB.DocumentClient();

exports.handler = function(event, context) {
  // ruleid: dynamodb-request-object
  documentClient.query(event.body.params, function(err, data) {
    if (err) {
      console.log(err);
    }
    console.log(data);
  });
}

exports.handler = function(event, context) {
  const params = Object.assign({hardcoded: 'params'}, event.body.params)
  // ruleid: dynamodb-request-object
  documentClient.query(params, function(err, data) {
    if (err) {
      console.log(err);
    }
    console.log(data);
  });
}

exports.handler = function(event, context) {
  // ok: dynamodb-request-object
  documentClient.query({
    // this is stupid, but we do not interested in such findings for this rule
    FilterExpression: `${event.body.name} = :s`,
    ExpressionAttributeValues: {
      ":s": { N: "1" }
    },
    KeyConditionExpression: 'STRING_VALUE'
  }, function(err, data) {
    if (err) console.log(err);
    else console.log(data);
  });
}

const { DynamoDBClient, QueryCommand } = require("@aws-sdk/client-dynamodb");
const { DynamoDBDocumentClient, PutCommand } = require("@aws-sdk/lib-dynamodb");

exports.handler = function(event, context) {

  const ddbClient = new DynamoDBClient({ region: 'REGION' });
  const ddbDocClient = DynamoDBDocumentClient.from(ddbClient);
  const { params } = event.body
  // todoruleid: dynamodb-request-object
  const data = await ddbDocClient.send(new QueryCommand(params));
  console.log("Success:", data.Items);

}

exports.handler = function(event, context) {

  const ddbClient = new DynamoDBClient({ region: 'REGION' });
  const ddbDocClient = DynamoDBDocumentClient.from(ddbClient);
  const params = event.body.params
  // ruleid: dynamodb-request-object
  const data = await ddbDocClient.send(new QueryCommand(params));
  console.log("Success:", data.Items);

}

exports.handler = function(event, context) {

  const ddbClient = new DynamoDBClient({ region: 'REGION' });
  const ddbDocClient = DynamoDBDocumentClient.from(ddbClient);
  const params = {
    KeyConditionExpression: "Title = :s",
    ExpressionAttributeValues: {
      ":s": { S: event.body.title }
    },
    ProjectionExpression: "Episode, Title",
    TableName: "TVSHOWS",
  }
  // ok: dynamodb-request-object
  const data = await ddbDocClient.send(new QueryCommand(params));
  console.log("Success:", data.Items);
}