Injection

How to Fix Injection in FastAPI [CVE-2021-32677]

[Updated Jun 2026] Updated CVE-2021-32677

Overview

CVE-2021-32677, CVE-2024-40627, and CVE-2024-42816 describe real-world Injection-related risks that affected FastAPI deployments in different ways. The first (CVE-2021-32677) is a CSRF-related flaw where a preflight-unaware server would parse JSON payloads even when the Content-Type was not application/json. If the app used cookie-based authentication, a malicious site could cause the browser to send a same-site or cross-origin request containing a payload, enabling actions on behalf of an authenticated user. The second (CVE-2024-40627) involves the OpaMiddleware allowing all HTTP OPTIONS requests unauthenticated, which could enable attackers to discover which entities exist by probing responses without proper policy evaluation. The third (CVE-2024-42816) is a fastapi-admin pro XSS vulnerability where user-provided data (e.g., Product Name) could be injected into HTML without proper escaping, allowing arbitrary script execution. The combined guidance here anchors remediation in concrete code, version upgrades, and safer rendering practices. For each vulnerability, the guide references the exact CVE and shows how to fix in real FastAPI code, including practical mitigations and testing steps.

Affected Versions

CVE-2021-32677: FastAPI < 0.65.2; CVE-2024-40627: OpaMiddleware < 2.0.1; CVE-2024-42816: fastapi-admin pro <= 0.1.4

Code Fix Example

FastAPI API Security Remediation
# Vulnerable and fixed code snippets demonstrating the three CVEs side by side
# Note: This is a concise illustrative example; adapt to your app structure.

# Vulnerable pattern for CVE-2021-32677 (parsing JSON regardless of Content-Type)
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

app = FastAPI()

@app.post("/csfr-prone")
async def csfr_prone(request: Request):
    data = await request.json()  # vulnerability: parses JSON even if Content-Type isn't JSON
    return {"received": data}

# Fixed pattern for CVE-2021-32677: guard JSON parsing on Content-Type
@app.post("/csfr-safe")
async def csfr_safe(request: Request):
    ctype = request.headers.get("content-type", "")
    if "application/json" not in ctype:
        return JSONResponse({"detail": "Unsupported Content-Type"}, status_code=400)
    data = await request.json()
    return {"received": data}

# Vulnerable pattern for CVE-2024-40627: OPTIONS bypass in OpaMiddleware (illustrative)
from fastapi.responses import JSONResponse

@app.middleware("http")
async def opa_vuln(request: Request, call_next):
    if request.method == "OPTIONS":
        return JSONResponse({"detail": "OK"}, status_code=200)  # no policy check
    return await call_next(request)

# Fixed pattern for CVE-2024-40627: enforce auth/policy on OPTIONS
@app.middleware("http")
async def opa_fixed(request: Request, call_next):
    if request.method == "OPTIONS" and not request.headers.get("Authorization"):
        return JSONResponse({"detail": "Unauthorized"}, status_code=401)
    return await call_next(request)

# Vulnerable pattern for CVE-2024-42816: unescaped user input rendered in HTML
from fastapi.responses import HTMLResponse

@app.get("/vuln-xss")
async def vuln_xss(request: Request):
    name = request.query_params.get("name", "")
    html = f"<div>Product: {name}</div>"  # vulnerable: injects input directly
    return HTMLResponse(content=html)

# Fixed pattern for CVE-2024-42816: escape/render via template (automatic escaping)
from fastapi.templating import Jinja2Templates
from fastapi import Depends

templates = Jinja2Templates(directory="templates")

@app.get("/fixed-xss")
async def fixed_xss(request: Request, _=Depends(lambda: None)):
    name = request.query_params.get("name", "")
    return templates.TemplateResponse("product.html", {"request": request, "name": name})

# Note: Ensure templates/product.html uses proper escaping (default in Jinja2).

CVE References

Choose which optional cookies to allow. You can change this any time.