HIGH mass assignmentfastapidynamodb

Mass Assignment in Fastapi with Dynamodb

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

Mass assignment occurs when a Fastapi endpoint directly maps user-supplied JSON into a DynamoDB request without filtering fields. In this stack, a developer often deserializes a request body into a Pydantic model for validation, then passes a dictionary or constructed item to boto3 operations such as put_item or update_item. If the model includes fields that are not intended to be client-settable (for example, admin, role, permissions, or internal metadata like created_at), an attacker can inject these keys into the JSON and have them persisted to DynamoDB.

Fastapi’s dependency on Pydantic means fields not declared in the model are typically ignored during parsing, but developers sometimes use model_dump() (or dict()) and forward the entire dictionary to DynamoDB. If the DynamoDB operation uses a flat attribute structure or relies on field names that overlap with sensitive attributes, the extra keys are accepted and stored. This becomes especially risky when combined with DynamoDB features like sparse indexes or conditional writes, where injected attributes can alter behavior, bypass guardrails, or escalate privileges. For example, an attacker could add a condition_expression key to an update payload if the application builds expressions from user input, leading to unintended writes.

In an unauthenticated scan context, middleBrick tests for endpoints that accept entity-like payloads and then attempt to write them into a simulated or monitored DynamoDB surface. Findings include missing field allowlists, overly permissive models, and usage patterns that propagate user-controlled keys into low-level database calls. These patterns align with the OWASP API Top 10 #1 (Broken Object Level Authorization) and map to compliance frameworks such as SOC2 and GDPR, because mass assignment can expose or modify data that should remain restricted.

Practical example of the vulnerable pattern:

from fastapi import FastAPI
from pydantic import BaseModel
import boto3
import json

app = FastAPI()
ddb = boto3.resource('dynamodb', region_name='us-east-1')
table = ddb.Table('Users')

class UserCreate(BaseModel):
    username: str
    email: str

@app.post('/users')
def create_user(payload: dict):
    # Risky: passes entire payload to DynamoDB
    table.put_item(Item=payload)
    return {'status': 'ok'}

If an attacker sends {"username": "alice", "email": "a@b.com", "admin": true}, the admin field is stored in DynamoDB because the endpoint did not restrict keys. middleBrick’s checks for authentication, BOLA/IDOR, and Property Authorization highlight such unchecked input flows.

Dynamodb-Specific Remediation in Fastapi — concrete code fixes

Remediation focuses on strict input filtering, explicit field mapping, and defensive handling before any DynamoDB operation. Use Pydantic models to define an allowlist, then construct the DynamoDB item from only the intended fields. Avoid passing raw dictionaries or using generic update payloads that can be influenced by an attacker.

Secure pattern with explicit attribute mapping for put_item:

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
import boto3
from datetime import datetime

app = FastAPI()
ddb = boto3.resource('dynamodb', region_name='us-east-1')
table = ddb.Table('Users')

class UserCreate(BaseModel):
    username: str
    email: EmailStr

def build_user_item(data: dict) -> dict:
    # Map only safe, expected fields
    return {
        'user_id': {'S': str(uuid4())},
        'username': {'S': data['username']},
        'email': {'S': data['email']},
        'created_at': {'S': datetime.utcnow().isoformat()},
        'admin': {'BOOL': False}
    }

@app.post('/users')
def create_user(payload: UserCreate):
    item = build_user_item(payload.model_dump())
    table.put_item(Item=item)
    return {'status': 'ok'}

For update_item, prefer explicit attribute expressions rather than composing expressions from user input. If dynamic field updates are required, validate each key against an allowlist:

ALLOWED_UPDATE_FIELDS = {'email', 'username'}

def safe_update(user_id: str, updates: dict) -> dict:
    filtered = {k: v for k, v in updates.items() if k in ALLOWED_UPDATE_FIELDS}
    if not filtered:
        raise ValueError('No updatable fields provided')
    update_expression = 'SET ' + ', '.join(f'{k}=:{k}' for k in filtered)
    expression_attribute_values = {f':{k}': {'S': str(v)} for k, v in filtered.items()}
    response = table.update_item(
        Key={'user_id': {'S': user_id}},
        UpdateExpression=update_expression,
        ExpressionAttributeValues=expression_attribute_values,
        ReturnValues='UPDATED_NEW'
    )
    return response['Attributes']

Additional DynamoDB-specific defenses include using sparse attributes for sensitive flags (so missing attributes are treated as false server-side), avoiding dynamic construction of condition expressions from user input, and validating numeric ranges to prevent logical bypasses. middleBrick scans for these patterns under BOLA/IDOR, BFLA/Privilege Escalation, and Property Authorization checks, ensuring that exposed operations do not permit privilege escalation via malformed items or expressions.

When integrating with CI/CD, the middleBrick GitHub Action can be configured to fail builds if findings related to mass assignment or missing field allowlists are detected, preventing insecure patterns from reaching production. The CLI provides JSON output for automated review, and the Web Dashboard tracks these findings over time to support compliance reporting.

Related CWEs: propertyAuthorization

CWE IDNameSeverity
CWE-915Mass Assignment HIGH

Frequently Asked Questions

How can I verify that my Fastapi endpoints are not vulnerable to mass assignment with DynamoDB?
Use middleBrick to scan your endpoints. The CLI command middlebrick scan <url> returns findings for Authentication, BOLA/IDOR, and Property Authorization. Check that your models are strict, fields are explicitly mapped before DynamoDB write operations, and no unexpected keys are propagated into put_item or update_item calls.
Does using Pydantic models alone prevent mass assignment in this stack?
Pydantic helps by validating declared fields, but mass assignment risk remains if you forward the entire payload or a generic dict to DynamoDB. Always map validated data to a controlled item structure and avoid passing raw or partially filtered dictionaries directly to database operations.