HIGH sql injectiondjangodynamodb

Sql Injection in Django with Dynamodb

SQL Injection in Django with DynamoDB — how this specific combination creates or exposes the vulnerability

SQL injection is commonly associated with relational databases, but when DynamoDB is used through an ORM or query layer in Django, developers can still introduce injection-like issues through unsafe string interpolation in query construction or raw expression building. Although DynamoDB itself uses a partitioned key-value model and does not have a SQL parser, injection risks arise when developers embed user input into key conditions, filter expressions, or construct low-level API parameters dynamically.

In a Django application using DynamoDB (for example via boto3 or a lightweight wrapper), a typical pattern might build a query dictionary using unchecked request data. If the code does not validate or parameterize values, an attacker can manipulate the structure of the condition expression to affect which items are returned or cause unexpected behavior. For example, concatenating a key condition string can unintentionally expose data or bypass intended filters.

Consider a DynamoDB table where partition keys represent tenant identifiers. If the application builds the key condition expression by string concatenation using raw input, an attacker may change the logical structure of the expression. While DynamoDB does not support arbitrary SQL, unsafe composition of expression attribute names and values can lead to over-privileged queries or data exposure. The framework does not inherently protect against these logic flaws, so validation and strict parameterization are essential.

An example of a risky pattern is constructing a filter expression by directly embedding user input into a string that becomes part of the request sent to DynamoDB. This can change the semantics of the query in ways the developer did not intend, such as affecting which subset of items is scanned or returned. Even though the backend is NoSQL, the impact can be significant: exposure of other users’ data, enumeration of records, or unexpected filtering behavior.

When using DynamoDB with Django, it is important to treat query inputs as untrusted and apply the same rigor as with SQL. Use strongly typed condition objects, validate input against expected formats, and avoid dynamic construction of key condition expressions. Rely on the SDK’s built-in mechanisms for expression values rather than string-based assembly. This ensures that user-controlled data never alters the structure of the request in unsafe ways.

DynamoDB-Specific Remediation in Django — concrete code fixes

To prevent injection-like issues when using DynamoDB in Django, adopt strict parameterization and input validation. Use expression attribute names and expression attribute values correctly, and avoid string interpolation for key conditions or filter logic. Below are concrete, safe patterns using the AWS SDK for Python (boto3) within a Django project.

Safe key condition construction

Always use placeholder syntax provided by the SDK and supply attribute values separately. This keeps data out of the expression structure and prevents unintended logic changes.

import boto3
from django.conf import settings

dynamodb = boto3.resource('dynamodb', region_name=settings.AWS_REGION)
table = dynamodb.Table('MyTable')

# Safe: using ExpressionAttributeNames and ExpressionAttributeValues
def get_tenant_items(tenant_id):
    response = table.query(
        KeyConditionExpression='#pk = :val',
        ExpressionAttributeNames={'#pk': 'tenant_id'},
        ExpressionAttributeValues={':val': tenant_id}
    )
    return response['Items']

Validated filter expressions

For filter logic, validate and map user input to known safe values or patterns, and use placeholders for any dynamic values.

import re

def build_filter(user_status):
    # Validate against an allowlist to prevent injection-like manipulation
    allowed = {'active', 'inactive', 'pending'}
    if user_status not in allowed:
        raise ValueError('Invalid status')
    return '#status = :status', {
        '#status': 'status',
        ':status': user_status
    }

def list_users(status):
    table = boto3.resource('dynamodb', region_name='us-east-1').Table('Users')
    condition, values = build_filter(status)
    response = table.scan(
        FilterExpression=condition,
        ExpressionAttributeNames={'#status': 'status'},
        ExpressionAttributeValues=values
    )
    return response['Items']

Avoiding dynamic expression names

Do not allow user input to dictate attribute names. If dynamic names are necessary, map them through a strict allowlist or dictionary lookup before use.

SAFE_NAMES = {
    'username': 'username',
    'email': 'email',
    'created_at': 'created_at'
}

def safe_query(index_name, value):
    if index_name not in SAFE_NAMES:
        raise ValueError('Invalid index')
    table = boto3.resource('dynamodb').Table('Items')
    response = table.query(
        IndexName=index_name,
        KeyConditionExpression='#idx = :v',
        ExpressionAttributeNames={'#idx': SAFE_NAMES[index_name]},
        ExpressionAttributeValues={':v': value}
    )
    return response['Items']

Framework-level safeguards

In Django, centralize DynamoDB access through services or repositories that enforce validation and expression safety. Use Django form or serializer validation to ensure only permitted data reaches query-building code. Logging and monitoring of unexpected patterns can also help detect attempted manipulation early.

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

Can SQL injection occur when using DynamoDB with Django?
While DynamoDB is a NoSQL database and does not parse SQL, injection-like issues can occur if user input is improperly embedded into query expressions, key conditions, or filter logic. This can lead to unintended data exposure or behavior. Use strict parameterization, expression attribute names/values, and input validation to prevent these risks.
What is the safest way to build DynamoDB queries in Django?
Use the SDK's ExpressionAttributeNames and ExpressionAttributeValues for all dynamic values, validate inputs against allowlists, avoid string concatenation for key conditions, and centralize query construction in validated service functions. Never insert raw user input into expression strings or attribute names.