Skip to content

FastAPI

Facts last verified 2026-07-29 against FastAPI 0.141.0 · Starlette 1.3.1 · uvicorn 0.52.0 · Pydantic 2.13.4

FastAPI sits between the two clusters either side of it. Django ships most protections on and the work is finding what got switched off. Express ships almost nothing and every control is something you add. FastAPI ships good defaults and almost no middleware — the settings it has are mostly right, and the things it does not have are simply absent.

So this cluster splits cleanly in two, and it is worth knowing which half a page is in before you read it.

Defaults that are already correct, where the page is a verify: debug is False, response_model filtering works when declared, cookies are signed, and there is no CORS policy at all until you add one.

Things that do not exist, where the page is a decision: no CSRF, no rate limiting, no request size cap, no host validation until you install it.

The mistake this cluster is built around is treating the second list as the first — concluding that because a framework does not ship a control, the control is not needed.

Terminal window
python3 -c "import fastapi, starlette, pydantic; print(fastapi.__version__, starlette.__version__, pydantic.VERSION)"
pip list 2>/dev/null | grep -iE '^(fastapi|starlette|uvicorn|pydantic|python-multipart) '

FastAPI 0.141.0 is current, on Starlette 1.3.1. Two version boundaries are worth knowing about. FastAPI requires Python 3.10+ from recent releases, so an environment on 3.9 will silently resolve to a much older FastAPI — pip install fastapi succeeding is not evidence you got a current one, and the version command above is the check. And Pydantic 2 changed validation error shapes from v1, which matters for validation error disclosure.

Before anything else on this page:

Terminal window
grep -rn -A6 'CORSMiddleware' app/ | grep -E 'allow_origins|allow_credentials'

allow_origins=["*"] together with allow_credentials=True does not send a wildcard. Starlette reflects the caller’s origin instead, which means any website can make authenticated requests with your users’ cookies and read the responses. It is the cluster’s threat page, and it is first because the dangerous configuration is one people arrive at by fixing a browser error rather than by choosing it.

request.client.host is either the peer address or a value the caller wrote in a header, and uvicorn’s --forwarded-allow-ips decides which. Rate limiting, IP allow-lists and every audit log inherit that decision, and both of the obvious values are wrong in a container: the 127.0.0.1 default ignores your proxy, and the '*' that fixes it trusts everyone.

Read proxy headers before the pages that depend on it.

Severity is the exposure a control closes, not how often it gets recommended. Two entries are rated low and say so on the page — including validation error disclosure, where the response mostly goes back to the client that sent it, and the real risk is what your logs then keep.

CORS configurationA permissive policy letting other origins read authenticated responsesSeverity: high
response_modelInternal fields serialised into responses because nothing declared what should be returnedSeverity: high
Debug mode and tracebacksSource paths, local frames and internal structure returned on any unhandled errorSeverity: high
Session cookiesSession contents readable by anyone holding the cookie, and sent over plaintextSeverity: high
Proxy headersSpoofed client IPs feeding rate limits, allow-lists and audit logsSeverity: high
Docs and OpenAPI endpointsA complete, machine-readable map of the API published to anyone who asksSeverity: medium
Trusted hostsAbsolute URLs built from an attacker-supplied Host headerSeverity: medium
CSRF protectionState-changing requests forged from another site using the visitor's cookiesSeverity: medium
Rate limitingCredential stuffing and brute force against login and token endpointsSeverity: medium
JWT libraryAn unhandled token exception returning 500 instead of 401, and an unpatchable timing-attack advisory in a transitive dependencySeverity: medium
Request size limitsMemory and disk exhaustion from unbounded request bodiesSeverity: low
Validation error disclosureSubmitted credentials reflected back in an error response and into logsSeverity: low
CORS origin reflectionAny website reading authenticated responses from your API in a visitor's browserSeverity: critical
0 of 13 applied

Python itself, the ASGI server’s TLS, the process manager, and the proxy in front of you. That is the server’s half rather than the application’s — see application vs server for the dividing line, and for the three controls that genuinely span both.