HIGH prototype pollutiondjangodynamodb

Prototype Pollution in Django with Dynamodb

Prototype Pollution in Django with Dynamodb — how this specific combination creates or exposes the vulnerability

Prototype pollution in a Django application using Amazon DynamoDB as the backend can occur when user-controlled input is merged into application objects that are later serialized into DynamoDB item structures. In JavaScript-based object handling this is a well-known class of vulnerability, but in Python/Django the same conceptual risk arises when dictionaries that represent item attributes are constructed from request data without strict validation. If a view builds an item dictionary by updating a base schema with values parsed from query parameters, JSON payloads, or form data, an attacker can inject keys such as __proto__, constructor, or other properties that affect object behavior in the application layer before the data is written to DynamoDB.

Consider a Django view that accepts JSON to update a DynamoDB item. If the view does not deeply validate or whitelist fields, an attacker can send a payload like {"price": 100, "__proto__": {"isAdmin": true}}. Python’s dict update mechanisms may propagate these keys into shared templates or class-like dictionaries used across the request, effectively polluting the logical prototype chain used by the application. When the polluted dictionary is marshaled into a DynamoDB PutItem or UpdateItem request, the malicious keys can be stored as attribute names, leading to unexpected behavior when the item is read and interpreted by downstream consumers, such as other services that rely on schema integrity.

DynamoDB itself does not execute code or interpret object prototypes, but the vulnerability manifests in how Django constructs and uses item dictionaries before sending them to the database. For example, if the application uses a utility that flattens or merges dictionaries for conditional update expressions (e.g., using UpdateExpression with placeholder values derived from user input), injected keys can alter the expression syntax or cause unintended attribute updates. This can lead to privilege escalation (e.g., modifying an is_admin attribute), data integrity issues, or bypass of business logic checks enforced in Python code rather than at the database level.

An example of unsafe construction in Django with DynamoDB:

import boto3
from django.http import JsonResponse

def update_item(request, item_id):
    data = request.POST.dict()  # Unsafe: directly uses user input
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table('Items')
    # Unsafe merge: attacker can inject keys like '__proto__'
    item = {'id': item_id, **data}
    table.put_item(Item=item)
    return JsonResponse({'status': 'updated'})

In this pattern, data is merged into item without validation. If an attacker controls a parameter named __proto__, it becomes a key in the DynamoDB item, polluting the application’s logical object model. Downstream processing that relies on Python object inheritance or shared dictionaries may behave unexpectedly, enabling security-relevant changes.

Dynamodb-Specific Remediation in Django — concrete code fixes

To protect Django applications using DynamoDB, enforce strict input validation and avoid merging raw user input into item dictionaries. Use schema definitions and allowlists to ensure only expected attributes are accepted, and serialize data with care to prevent unintended key propagation.

1. Validate and whitelist fields before constructing DynamoDB items. Define an allowed set of attributes and map known types explicitly.

from django.http import JsonResponse
import boto3

ALLOWED_FIELDS = {'name', 'price', 'category'}

def safe_update_item(request, item_id):
    allowed = ALLOWED_FIELDS
    raw = request.POST.dict()
    # Build item using only allowed keys with type checks
    item = {'id': item_id}
    for key, value in raw.items():
        if key in allowed:
            if key == 'price':
                item[key] = float(value)
            else:
                item[key] = value
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table('Items')
    table.put_item(Item=item)
    return JsonResponse({'status': 'updated'})

2. Use DynamoDB expression attribute values instead of merging dictionaries to avoid injection via key names. This keeps user data in values, not in attribute names.

import boto3

def update_with_expressions(request, item_id):
    data = request.POST.dict()
    # Only permit known safe attributes
    valid_updates = {k: v for k, v in data.items() if k in {'price', 'category'}}
    if not valid_updates:
        return JsonResponse({'error': 'no valid fields'}, status=400)
    set_clauses = [f'#{k} = :{k}' for k in valid_updates.keys()]
    expression = f'UPDATE table SET {', '.join(set_clauses)} WHERE id = :id'
    expression_attribute_names = {f'#{k}': k for k in valid_updates.keys()}
    expression_attribute_values = {f':{k}': v for k, v in valid_updates.items()}
    expression_attribute_values[':id'] = item_id
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table('Items')
    table.update_item(
        Key={'id': item_id},
        UpdateExpression=expression,
        ExpressionAttributeNames=expression_attribute_names,
        ExpressionAttributeValues=expression_attribute_values
    )
    return JsonResponse({'status': 'updated'})

3. Sanitize keys before any dictionary merging or serialization. Reject or rename keys that could pollute object prototypes or application semantics.

def sanitize_keys(payload):
    dangerous = {'__proto__', 'constructor', 'prototype'}
    return {k: v for k, v in payload.items() if k not in dangerous}

def update_with_sanitized(request, item_id):
    raw = sanitize_keys(request.POST.dict())
    item = {'id': item_id, **raw}
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table('Items')
    table.put_item(Item=item)
    return JsonResponse({'status': 'updated'})

These approaches ensure that user input never directly dictates attribute names in DynamoDB item structures, preventing prototype pollution-style attacks while maintaining compatibility with DynamoDB’s attribute-value model.

Frequently Asked Questions

Does middleBrick detect prototype pollution in Django/Dynamodb scans?
Yes. middleBrick runs security checks including Input Validation and Property Authorization. If your scan detects unsafe merging of user input into item dictionaries that map to DynamoDB attributes, you will receive a finding with severity, details, and remediation guidance.
Can I test LLM security for an API used by a Django backend with DynamoDB?
Yes. If your Django backend exposes an endpoint that interacts with LLMs, middleBrick’s LLM/AI Security checks probe for prompt injection, system prompt leakage, and output risks. Use the CLI (middlebrick scan ) or the GitHub Action to include these checks in CI/CD.