Insecure Direct Object Reference in Fastapi with Dynamodb
Insecure Direct Object Reference in Fastapi with Dynamodb — how this specific combination creates or exposes the vulnerability
Insecure Direct Object Reference (IDOR) occurs when an API exposes a reference to an internal object—such as a DynamoDB primary key or sort key—and allows an authenticated subject to access or modify that object without verifying authorization. In a FastAPI application that uses DynamoDB, this commonly arises when route parameters (e.g., user_id or document_id) are passed directly into DynamoDB requests without confirming that the requesting user has permission to access the corresponding item.
Consider a FastAPI endpoint that retrieves a user profile using a path parameter user_id. If the endpoint performs a GetItem or Query on a DynamoDB table using user_id as the key but does not confirm that the authenticated subject owns that user_id, the endpoint becomes vulnerable to IDOR. An attacker who can obtain or guess another user’s ID can issue requests and read or influence other users’ data. This risk is compounded because DynamoDB responses do not inherently enforce ownership; it is the application’s responsibility to validate access controls for each request.
Because FastAPI often deserializes path, query, or body parameters into Pydantic models, developers may mistakenly trust these values as safe identifiers. If authorization logic is omitted or applied inconsistently—such as checking group membership but not matching the specific item’s ownership—an IDOR vulnerability exists. For example, an endpoint that supports tenant-aware operations must ensure that a tenant_id from the path is validated against the DynamoDB item’s tenant attribute, rather than relying on network-level isolation or assuming that a list query is inherently safe.
IDOR is frequently identified by middleBrick in the BOLA/IDOR security check, which examines whether object-level authorization is enforced for direct object references. When scanning a FastAPI service backed by DynamoDB, middleBrick tests unauthenticated and authenticated scenarios to detect endpoints where object references can be manipulated to access unauthorized data. Findings include references to the specific DynamoDB key schema and guidance to enforce ownership or tenant checks before performing GetItem, Query, or UpdateItem operations.
Dynamodb-Specific Remediation in Fastapi — concrete code fixes
To remediate IDOR with DynamoDB in FastAPI, enforce authorization checks that tie each DynamoDB request to the requesting subject. This includes validating that the authenticated user’s ID matches the item’s ownership attribute, applying tenant scoping, and avoiding broad or indirect queries that can expose other users’ items.
Below are concrete, working examples using the AWS SDK for Python (Boto3) with FastAPI. They demonstrate how to safely retrieve and update items by ensuring the request subject is explicitly verified against the DynamoDB record before proceeding.
Example 1: Safe item retrieval with ownership check
In this pattern, the endpoint extracts both the authenticated subject (e.g., from a JWT or session) and the requested identifier from the path. It then queries the DynamoDB table using a composite key that includes the subject, ensuring that users can only access their own items.
from fastapi import FastAPI, Depends, HTTPException, status
from pydantic import BaseModel
import boto3
from botocore.exceptions import ClientError
app = FastAPI()
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
table_name = 'user_profiles'
class UserProfile(BaseModel):
user_id: str
name: str
email: str
def get_current_user_id() -> str:
# Replace with your authentication logic (e.g., JWT verification)
return "user-123"
@app.get('/profiles/{user_id}', response_model=UserProfile)
def get_profile(user_id: str, current_user_id: str = Depends(get_current_user_id)):
if user_id != current_user_id:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail='Access denied')
table = dynamodb.Table(table_name)
try:
response = table.get_item(Key={'user_id': user_id})
except ClientError as e:
raise HTTPException(status_code=500, detail='Database error')
item = response.get('Item')
if item is None:
raise HTTPException(status_code=404, detail='Profile not found')
return UserProfile(**item)
Example 2: Scoped query with tenant ownership
When records are scoped by a tenant or group, include the tenant identifier both in the DynamoDB key design and in runtime checks. This prevents a subject from enumerating or modifying items belonging to other tenants.
from fastapi import FastAPI, Depends, HTTPException, status
from pydantic import BaseModel
import boto3
from botocore.exceptions import ClientError
app = FastAPI()
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
table_name = 'tenant_documents'
class Document(BaseModel):
tenant_id: str
document_id: str
content: str
def get_current_tenant_id() -> str:
# Replace with your tenant resolution logic
return "tenant-abc"
@app.get('/documents/{document_id}', response_model=Document)
def get_document(document_id: str, tenant_id: str = Depends(get_current_tenant_id)):
table = dynamodb.Table(table_name)
try:
response = table.get_item(Key={'tenant_id': tenant_id, 'document_id': document_id})
except ClientError as e:
raise HTTPException(status_code=500, detail='Database error')
item = response.get('Item')
if item is None:
raise HTTPException(status_code=404, detail='Document not found')
return Document(**item)
General mitigation guidance
- Always verify the requesting subject against the item’s ownership or tenant attributes before performing
GetItem,Query,UpdateItem, orDeleteItem. - Design your DynamoDB key schema to include ownership context (e.g., composite keys with
user_idas partition key) so that queries are naturally scoped. - Avoid using client-supplied identifiers as the sole means of object lookup; use them in combination with server-side subject context.
- Apply the principle of least privilege to the IAM role used by FastAPI so that it cannot read or write items outside the intended scope.
middleBrick’s checks align with findings related to OWASP API Top 10 A01:2023 — Broken Object Level Authorization. By combining these code-level patterns with continuous scanning, you reduce the likelihood of IDOR-related data exposure in DynamoDB-backed FastAPI services.
Related CWEs: bolaAuthorization
| CWE ID | Name | Severity |
|---|---|---|
| CWE-250 | Execution with Unnecessary Privileges | HIGH |
| CWE-639 | Insecure Direct Object Reference | CRITICAL |
| CWE-732 | Incorrect Permission Assignment | HIGH |