Request Smuggling in Fastapi
How Request Smuggling Manifests in Fastapi
Request smuggling in FastAPI typically exploits the framework's interaction with ASGI servers like Uvicorn and HTTP parsing ambiguities. FastAPI applications often run behind reverse proxies (nginx, HAProxy, AWS ALB) that may interpret Content-Length and Transfer-Encoding headers differently than the FastAPI server itself.
The most common FastAPI-specific scenario involves multipart form data handling. When FastAPI processes multipart requests, it uses the python-multipart library to parse content. An attacker can craft a request where the Content-Length header indicates a certain size, but the Transfer-Encoding header suggests chunked transfer encoding. This creates ambiguity about where the request body ends.
POST /api/upload HTTP/1.1
Host: example.com
Content-Length: 50
Transfer-Encoding: chunked
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain
malicious content
------WebKitFormBoundary7MA4YWxkTrZu0gW--
In this example, the proxy might use Content-Length (50 bytes) while FastAPI's ASGI server processes Transfer-Encoding (chunked). The discrepancy causes the second request in a sequence to be interpreted as part of the first request's body, leading to request smuggling.
Another FastAPI-specific vector involves FastAPI's dependency injection system. When using Depends() with file uploads, the framework's request body parsing can be manipulated. Consider this vulnerable pattern:
@app.post("/upload")
async def upload(file: UploadFile = File(...), data: dict = Body(...)):
# FastAPI parses both file and body
return await process_upload(file, data)
An attacker can exploit the dual parsing by crafting headers that cause FastAPI to misinterpret the request boundaries, potentially injecting malicious payloads into the dependency injection chain.
FastAPI's automatic OpenAPI generation can also be leveraged. The framework's documentation endpoints (/docs, /openapi.json) might inadvertently expose internal API structures that assist in crafting smuggling attacks. An attacker can use the OpenAPI spec to understand expected request formats and then craft smuggling payloads that exploit parsing differences.
Fastapi-Specific Detection
Detecting request smuggling in FastAPI requires both manual testing and automated scanning. middleBrick's black-box scanning approach is particularly effective because it tests the actual runtime behavior without requiring source code access.
middleBrick scans FastAPI endpoints by sending carefully crafted requests that test Content-Length vs Transfer-Encoding ambiguities. The scanner specifically targets FastAPI's multipart form handling and dependency injection patterns. Here's how you would scan a FastAPI endpoint:
# Using middleBrick CLI to scan FastAPI endpoint
npx middlebrick scan https://api.example.com/docs
The scanner tests 12 security categories simultaneously, including authentication bypass attempts that could be combined with smuggling attacks. For FastAPI specifically, middleBrick checks:
- Multipart form data parsing vulnerabilities
- Content-Length/Transfer-Encoding header conflicts
- ASGI server boundary detection failures
- OpenAPI endpoint exposure that could aid attack planning
- Dependency injection chain manipulation possibilities
Manual detection involves sending test requests with conflicting headers and observing server responses. Use tools like Burp Suite or curl to craft requests:
curl -X POST https://api.example.com/upload \
-H "Content-Length: 100" \
-H "Transfer-Encoding: chunked" \
-H "Content-Type: multipart/form-data; boundary=----test" \
--data-binary "----test\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\ncontent\r\n----test--\r\nPOST /malicious HTTP/1.1\r\nHost: attacker.com\r\n\r\nmalicious body"
Watch for inconsistent responses, timeouts, or unexpected behavior that indicates boundary confusion. FastAPI's debug mode (debug=True) can sometimes leak internal error details that reveal parsing issues.
Network-level detection using Wireshark or tcpdump can capture the actual byte streams being processed by FastAPI's ASGI server versus what the proxy forwards, revealing smuggling attempts in transit.
Fastapi-Specific Remediation
Remediating request smuggling in FastAPI requires a multi-layered approach. Start with reverse proxy configuration to ensure consistent header interpretation:
# nginx configuration to prevent smuggling
proxy_set_header Transfer-Encoding "";
proxy_set_header Content-Length $content_length;
proxy_ignore_headers Transfer-Encoding;
This forces nginx to use only Content-Length and ignore Transfer-Encoding, eliminating the ambiguity that causes smuggling.
At the FastAPI application level, implement strict request validation middleware:
from fastapi import Request, HTTPException
from fastapi.middleware import Middleware
class RequestSmugglingMiddleware:
async def __call__(self, request: Request, call_next):
# Validate Content-Length matches actual body size
content_length = request.headers.get('content-length')
if content_length:
try:
expected_length = int(content_length)
body = await request.body()
if len(body) != expected_length:
raise HTTPException(status_code=400, detail="Content-Length mismatch")
except ValueError:
raise HTTPException(status_code=400, detail="Invalid Content-Length")
# Check for conflicting headers
if 'transfer-encoding' in request.headers and 'content-length' in request.headers:
raise HTTPException(status_code=400, detail="Conflicting transfer encodings")
return await call_next(request)
app.add_middleware(RequestSmugglingMiddleware)
For multipart form data specifically, use FastAPI's built-in validation with explicit size limits:
from fastapi import File, UploadFile, Form, Body
from fastapi.exceptions import RequestValidationError
@app.post("/upload")
async def upload_file(file: UploadFile = File(...),
metadata: dict = Body(...),
max_size: int = 1048576): # 1MB limit
# Validate file size before processing
if file.size > max_size:
raise HTTPException(status_code=413, detail="File too large")
# Process file securely
Enable FastAPI's built-in security features by setting appropriate timeouts and limits in your ASGI server configuration (uvicorn settings):
# uvicorn config to prevent large request attacks
--timeout-keep-alive 30
--timeout-graceful-shutdown 30
--limit-concurrency 1000
Consider using a WAF or API gateway that specifically detects and blocks request smuggling patterns before they reach FastAPI. Cloudflare, AWS API Gateway, and similar services offer request validation that can catch smuggling attempts.
Finally, implement comprehensive logging to detect smuggling attempts:
import logging
logger = logging.getLogger(__name__)
@app.middleware("http")
async def smuggling_logger(request: Request, call_next):
logger.info(f"Request: {request.method} {request.url} Headers: {dict(request.headers)}")
try:
response = await call_next(request)
except Exception as e:
logger.error(f"Request error: {e}")
raise
return response
These remediation steps, combined with regular middleBrick scanning, create a defense-in-depth approach to request smuggling in FastAPI applications.
Frequently Asked Questions
How can I test my FastAPI application for request smuggling vulnerabilities?
npx middlebrick scan https://your-api.com/docs. The scanner tests Content-Length vs Transfer-Encoding conflicts, multipart form data parsing, and ASGI server boundary detection. For manual testing, use tools like Burp Suite to craft requests with conflicting headers and observe how your FastAPI server responds.