Stack Overflow in Fastapi
How Stack Overflow Manifests in Fastapi
Stack Overflow vulnerabilities in FastAPI applications typically occur when user input is directly used in recursive operations, deeply nested data structures, or unbounded iteration without proper limits. FastAPI's asynchronous nature and dependency injection system can sometimes mask these issues until they're exploited in production.
A common FastAPI-specific pattern involves recursive dependency injection. Consider this vulnerable code:
from fastapi import FastAPI, Depends
from pydantic import BaseModel
app = FastAPI()
class RecursiveModel(BaseModel):
data: str
next: 'RecursiveModel' = None # Recursive reference
async def create_recursive_model(depth: int = 1000):
if depth == 0:
return None
return RecursiveModel(
data=f"depth-{depth}",
next=await create_recursive_model(depth - 1)
)
@app.post("/vulnerable")
async def vulnerable_endpoint(model: RecursiveModel = Depends(create_recursive_model)):
return {"status": "processed"}
This creates a recursion depth of 1000, which can trigger Python's maximum recursion limit and cause a stack overflow. FastAPI's dependency injection system will attempt to resolve this dependency chain, potentially exhausting system resources.
Another FastAPI-specific scenario involves Pydantic models with recursive validation. When FastAPI parses request bodies, it uses Pydantic's validation system, which can be exploited through carefully crafted recursive schemas:
from pydantic import BaseModel
from typing import Optional
class RecursiveModel(BaseModel):
value: int
child: Optional['RecursiveModel'] = None
@app.post("/recursive")
async def recursive_endpoint(model: RecursiveModel):
return {"received": model}
An attacker can send a JSON payload with extreme nesting levels, causing the Pydantic parser to consume excessive memory and processing time during validation.
Fastapi-Specific Detection
Detecting Stack Overflow vulnerabilities in FastAPI requires both static analysis and runtime monitoring. FastAPI's dependency injection system and Pydantic model validation create specific attack surfaces that need targeted scanning.
Using middleBrick's CLI tool, you can scan your FastAPI endpoints for Stack Overflow vulnerabilities:
npx middlebrick scan https://your-api.com/openapi.json
The scanner will analyze your OpenAPI specification and test endpoints for recursive input patterns, unbounded data structures, and potential stack exhaustion scenarios. middleBrick specifically checks for:
- Recursive Pydantic model definitions in your API schema
- Endpoints accepting deeply nested JSON structures
- Dependencies with potential for infinite recursion
- Lack of input size limits on request bodies
- Excessive recursion depth in dependency injection chains
For runtime detection, FastAPI provides middleware that can monitor request processing:
from fastapi import FastAPI, Request, Response
from fastapi.middleware import Middleware
import time
class StackOverflowDetectionMiddleware:
def __init__(self, app: FastAPI):
self.app = app
async def __call__(self, request: Request, call_next):
start_time = time.time()
try:
response = await call_next(request)
processing_time = time.time() - start_time
if processing_time > 2.0: # Threshold for suspicious processing
# Log potential stack overflow attempt
print(f"Suspicious processing time: {processing_time}s for {request.url}")
return response
except Exception as e:
if "recursion" in str(e).lower():
# Stack overflow detected
print(f"Stack overflow detected: {e}")
return Response(
status_code=400,
content="{"error": "Request too complex"}"
)
raise
app.add_middleware(StackOverflowDetectionMiddleware)
Fastapi-Specific Remediation
FastAPI provides several native mechanisms to prevent Stack Overflow vulnerabilities. The key is implementing input validation, recursion limits, and safe dependency injection patterns.
First, use Pydantic's max_recursion setting to limit recursive parsing:
from pydantic import BaseModel, validator
from typing import Optional
class SafeRecursiveModel(BaseModel):
value: int
child: Optional['SafeRecursiveModel'] = None
class Config:
max_recursion = 10 # Limit recursion depth to 10 levels
@app.post("/safe-recursive")
async def safe_recursive_endpoint(model: SafeRecursiveModel):
return {"received": model}
For dependency injection, use FastAPI's Depends with explicit limits:
from fastapi import Depends, FastAPI
from typing import Optional
app = FastAPI()
async def create_limited_recursive_model(depth: int = 10):
if depth <= 0:
return None
return {
"depth": depth,
"child": await create_limited_recursive_model(depth - 1)
}
@app.post("/limited-dependency")
async def limited_dependency(model: dict = Depends(create_limited_recursive_model)):
return {"processed": model}
Implement request size limits using FastAPI's middleware:
from fastapi import FastAPI, Request, Response
from fastapi.middleware import Middleware
class RequestSizeLimitMiddleware:
def __init__(self, app: FastAPI, max_size: int = 1_000_000):
self.app = app
self.max_size = max_size
async def __call__(self, request: Request, call_next):
content_length = request.headers.get("content-length")
if content_length and int(content_length) > self.max_size:
return Response(
status_code=413,
content="{"detail": "Request entity too large"}"
)
return await call_next(request)
app.add_middleware(RequestSizeLimitMiddleware)
For JSON payloads, use Pydantic's max_length validator:
from pydantic import BaseModel, validator
from typing import List
class SafeListModel(BaseModel):
items: List[str]
@validator('items', pre=True, each_item=True)
def check_item_length(cls, v):
if len(v) > 1000: # Limit string length
raise ValueError('Item too long')
return v
@validator('items', pre=True)
def check_list_length(cls, v):
if len(v) > 100: # Limit list size
raise ValueError('Too many items')
return v