Pii Leakage in Fastapi with Dynamodb
Pii Leakage in Fastapi with Dynamodb — how this specific combination creates or exposes the vulnerability
A FastAPI service that uses Amazon DynamoDB can inadvertently expose personally identifiable information (PII) through a combination of application-level data handling and DynamoDB access patterns. PII leakage occurs when endpoints return entire DynamoDB items or overly broad query results without filtering sensitive fields, and when the API does not enforce field-level authorization or consistent encryption practices. For example, an endpoint like /users/{user_id} might call get_item on a DynamoDB table that stores profile data including email, phone, and address, and then return the full item to the client. If the route does not explicitly omit or redact sensitive keys, the response becomes a direct source of PII leakage.
DynamoDB-specific factors that contribute to risk include permissive IAM policies that allow broader read access than intended, sparse attribute-level permissions in the application layer, and the use of sparse projections in queries that pull more attributes than necessary. When FastAPI merges raw DynamoDB responses into JSON-serializable dictionaries, any PII present is automatically exposed to the client unless the code explicitly prunes or masks it. Additionally, features like DynamoDB Streams can propagate sensitive data to downstream consumers (e.g., analytics or logging systems) if those consumers are not configured to filter or encrypt PII. Misconfigured encryption settings, such as disabling encryption at rest or failing to enforce encryption in transit via HTTPS, can also increase the likelihood of exposure during data retrieval.
The 12 security checks in middleBrick test this combination by examining unauthenticated surfaces and OpenAPI specifications, identifying endpoints that return sensitive data without sufficient authorization or input constraints. For instance, an OpenAPI schema that defines a 200 response model containing email and ssn without indicating redaction or conditional inclusion flags can be flagged for PII exposure. Runtime probes may validate that query results do not leak credentials or contact details, and whether rate limiting and property-level authorization are in place to prevent excessive data retrieval. This approach highlights how FastAPI route implementations and DynamoDB access patterns jointly determine whether PII is safely contained or unintentionally exposed.
Dynamodb-Specific Remediation in Fastapi — concrete code fixes
To mitigate PII leakage when using FastAPI with DynamoDB, implement explicit field filtering, secure IAM policies, and encryption enforcement. Below are concrete code examples that demonstrate secure patterns.
1. Retrieve only necessary attributes with ProjectionExpression
Use ProjectionExpression in get_item and query requests to limit DynamoDB responses to required, non-sensitive attributes. This reduces the data surface exposed to the API layer.
import boto3
from fastapi import FastAPI, HTTPException
app = FastAPI()
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
table = dynamodb.Table('users')
@app.get('/users/{user_id}')
def get_user_public(user_id: str):
response = table.get_item(
Key={'user_id': user_id},
ProjectionExpression='user_id, display_name, avatar_url'
)
item = response.get('Item')
if item is None:
raise HTTPException(status_code=404, detail='User not found')
return item
2. Explicitly redact or rename sensitive fields before returning
When broader access is required, transform the item in FastAPI to remove or rename PII fields such as email and phone before serialization.
import boto3
from fastapi import FastAPI, HTTPException
app = FastAPI()
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
table = dynamodb.Table('users')
def sanitize_user_item(item: dict) -> dict:
return {
'user_id': item.get('user_id'),
'display_name': item.get('display_name'),
'avatar_url': item.get('avatar_url')
# email, phone, and ssn are intentionally omitted
}
@app.get('/users/{user_id}')
def get_user_sanitized(user_id: str):
response = table.get_item(Key={'user_id': user_id})
item = response.get('Item')
if item is None:
raise HTTPException(status_code=404, detail='User not found')
return sanitize_user_item(item)
3. Enforce encryption in transit and at rest via resource policies and client configuration
Ensure that the DynamoDB client uses HTTPS and that the table enforces encryption at rest. While infrastructure settings are outside FastAPI, the application can require secure endpoints and validate responses.
import boto3
from botocore.exceptions import ClientError
from fastapi import FastAPI
app = FastAPI()
def get_secure_dynamodb_client():
return boto3.client(
'dynamodb',
region_name='us-east-1',
endpoint_url='https://dynamodb.us-east-1.amazonaws.com' # HTTPS enforced
)
@app.get('/health')
def check_dynamodb_encryption():
client = get_secure_dynamodb_client()
try:
# A lightweight call to verify connectivity and TLS
client.list_tables(Limit=1)
return {'status': 'secure'}
except ClientError as e:
raise HTTPException(status_code=503, detail=f'DynamoDB connection error: {e}')
4. Apply least-privilege IAM via role-specific policies
Define IAM policies that grant only the necessary actions on specific resources. FastAPI assumes the runtime environment provides a properly scoped role or user, avoiding broad read permissions on user tables.
# Example IAM policy (conceptual, not code executed by FastAPI)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:Query"
],
"Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/users",
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": ["${cognito-identity.amazonaws.com:sub}"]
}
}
}
]
}
By combining these practices—field projection, explicit redaction, secure client configuration, and least-privilege access—you significantly reduce the risk of PII leakage in FastAPI applications backed by DynamoDB.
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |