Ssrf Server Side in Fastapi with Dynamodb
Ssrf Server Side in Fastapi with Dynamodb — how this specific combination creates or exposes the vulnerability
Server-side request forgery (SSRF) in a FastAPI service that accesses DynamoDB can occur when the application builds HTTP requests to third-party services using data supplied by the caller, and that data is also used to construct or influence DynamoDB operations. For example, an endpoint that accepts a URL or hostname to fetch external metadata, then uses that input to decide which DynamoDB table or index to query, can allow an attacker to direct internal service calls. If the FastAPI code resolves the supplied host to an internal AWS metadata service address (e.g., 169.254.169.254), an SSRF becomes a potential vector to reach sensitive metadata that may be linked to IAM roles attached to the DynamoDB access identity.
In a typical integration, the application uses the AWS SDK for Python (boto3) with a resource or client against DynamoDB. If request parameters are passed into low-level calls such as get_item or query without strict validation of the table name and key schema, an attacker may combine SSRF with DynamoDB reconnaissance. An input value that is used both to perform an outbound HTTP call and to select a DynamoDB table can expose patterns that bypass intended access boundaries. For instance, a crafted hostname can lead to requests against the instance metadata service, while the same input selects a DynamoDB table that contains sensitive configurations, effectively chaining SSRF with unauthorized data access.
Moreover, DynamoDB streams and Time to Live (TTL) behaviors can amplify the impact if SSRF allows triggering or suppressing specific item changes. Because FastAPI routes often deserialize JSON bodies directly into models, missing schema constraints on string fields used for table names or key attribute values can make the endpoint vulnerable. The risk is not in DynamoDB itself, but in how FastAPI constructs requests and passes user-influenced data to both the HTTP client and the AWS SDK, creating a path where SSRF and DynamoDB access intersect in an unsafe manner.
Dynamodb-Specific Remediation in Fastapi — concrete code fixes
To mitigate SSRF when integrating FastAPI with DynamoDB, validate and sanitize all inputs that affect both outbound HTTP calls and DynamoDB operations. Use strict allowlists for table names and key attribute values, and avoid using raw user input in low-level boto3 calls. Below are concrete code examples that demonstrate safe patterns.
- Validate table name against an allowlist and use the DynamoDB resource safely in FastAPI:
from fastapi import FastAPI, HTTPException, Query
import boto3
from pydantic import BaseModel
app = FastAPI()
# Define an allowlist of tables that the service is allowed to access
ALLOWED_TABLES = {"users", "products", "audit_log"}
class Item(BaseModel):
pk: str
sk: str
data: dict
# Initialize client outside the route for connection reuse
ddb = boto3.resource("dynamodb", region_name="us-east-1")
@app.get("/items/{table_name}")
def get_item(
table_name: str = Query(..., description="Table name from allowed list"),
pk: str = Query(..., description="Partition key"),
sk: str = Query(..., description="Sort key")
):
if table_name not in ALLOWED_TABLES:
raise HTTPException(status_code=400, detail="Table not allowed")
table = ddb.Table(table_name)
try:
response = table.get_item(Key={"pk": pk, "sk": sk})
except Exception as e:
raise HTTPException(status_code=500, detail="Database error")
item = response.get("Item")
if not item:
raise HTTPException(status_code=404, detail="Item not found")
return item
- Use a factory or dependency to resolve table references safely, avoiding direct concatenation of user input into URLs or ARNs:
from fastapi import Depends
def get_table(table_name: str):
if table_name not in ALLOWED_TABLES:
raise HTTPException(status_code=403, detail="Access denied")
return ddb.Table(table_name)
@app.get("/items/{table_name}/safe")
def read_item(
table_name: str,
item: Item,
table = Depends(get_table)
):
response = table.get_item(Key={"pk": item.pk, "sk": item.sk})
return response.get("Item")
- When calling external services, avoid using user-controlled hosts directly. Use a configured HTTPX or requests client with a strict base URL and timeouts, and ensure any SSRF-prone parameters are validated against a host allowlist:
import httpx
EXTERNAL_BASE = "https://api.example.com"
@app.get("/external/{path:path}")
def proxy_external(
path: str,
client: httpx.Client = Depends(lambda: httpx.Client(timeout=5.0))
):
# Validate path segments to prevent directory traversal or host switching
if ".." in path or "//" in path:
raise HTTPException(status_code=400, detail="Invalid path")
url = f"{EXTERNAL_BASE}/{path}"
try:
resp = client.get(url)
resp.raise_for_status()
except httpx.RequestError:
raise HTTPException(status_code=502, detail="Upstream error")
return resp.json()
Combine these practices with runtime monitoring and the middleBrick CLI to scan endpoints for SSRF and DynamoDB-related findings. The CLI can be integrated into scripts to automate detection of risky patterns, while the GitHub Action can enforce security gates in CI/CD pipelines. For teams needing continuous visibility, the Pro plan provides ongoing monitoring and alerts, and the MCP Server enables scanning directly from AI coding assistants within your development environment.