FastAPI looks small. You install fastapi, you write a handler, you deploy. In reality your pip install fastapi drags in Starlette, Pydantic, typing extensions, and whatever ASGI server you pair it with. Add the community ecosystem — fastapi-users, fastapi-cache, slowapi, sqlmodel — and the dependency tree for a production FastAPI app easily runs 60 to 120 packages. Each of those is a supply chain risk.
I manage FastAPI services for a security-conscious platform and I have spent enough time debugging transitive upgrades to write this guide. It is not theoretical.
The Three Packages You Must Track Closely
FastAPI itself is a thin shim over three projects, and its security depends on theirs.
Starlette is the ASGI framework underneath. FastAPI pins it in a range (starlette>=0.37.2,<0.38.0 as of FastAPI 0.111). When Starlette ships a fix, FastAPI often has to release to widen the range. CVE-2024-47874 (Starlette DoS via multipart form parsing) is the kind of issue where the FastAPI user thinks they are patching "FastAPI" but actually they need a matching Starlette bump, and the version pins do not always align cleanly.
Pydantic handles validation. Pydantic v1 and v2 are different runtimes that share an import path, and the v2 migration in 2023 broke compatibility for a lot of libraries. If you are still on FastAPI 0.99 to pin to Pydantic v1, you are running a branch that no longer receives security backports.
Uvicorn or Hypercorn serves the ASGI app. Uvicorn has had its own issues — not many, but the --reload mode should never be run in production, and teams still do it by accident.
Treat these four packages — FastAPI, Starlette, Pydantic, the ASGI server — as first-class. Track their CVE feeds. Do not let automated bots bump them without someone looking at the release notes.
Why Are You Trusting These Plugins?
The FastAPI plugin ecosystem is energetic and underreviewed. fastapi-users is widely used for auth and has had legitimate releases with security implications — including changes to password hashing defaults that silently affected existing databases. fastapi-cache2 is maintained by a single person. fastapi-jwt-auth has been effectively unmaintained since 2022, with open critical issues, and teams still pull it in because a Stack Overflow answer from 2021 recommended it.
Before you install a FastAPI plugin, check three things. When was the last commit? How many open security issues? Does it pin FastAPI or Starlette, and if so to what? A plugin pinned to fastapi<0.90 is a plugin that is holding back your entire dependency tree.
For authentication, Authlib and python-jose have both had CVEs (CVE-2022-29217 in python-jose, CVE-2024-33663 in python-jose ECDSA verification). python-jose is effectively unmaintained as of late 2023, and the Python security community has been recommending PyJWT or joserfc instead. If your FastAPI app uses python-jose, migrate.
Pinning Strategy That Does Not Collapse
The two common failure modes: pin nothing and get silently upgraded into breakage, or pin everything with hashes and become unable to apply security patches without an afternoon of manual work. Neither is acceptable.
What works in production is layered. Your top-level requirements (pyproject.toml or requirements.in) use range specifiers with upper bounds that match the library's stated compatibility — fastapi>=0.111,<0.112. Your lock file (requirements.txt from pip-compile, or poetry.lock, or uv.lock) pins exact versions with hashes. You regenerate the lock file weekly as a scheduled PR, and you have a separate fast-track process for security-only updates.
The fast-track matters. When CVE-2024-24762 hit python-multipart (FastAPI uses it for form parsing), teams on strictly hash-pinned setups took a week to roll out the patch because the update had to go through the normal release train. A security-only PR template that bumps a single package and runs the full test suite should merge same-day.
Does Your ASGI Server Know What It Is Doing?
Uvicorn behind a reverse proxy is standard. Uvicorn exposed directly to the internet is a bad idea, mostly because it does not implement the full set of protections you want: connection timeouts are loose, request size limits are not enforced at the ASGI layer, slowloris mitigations are minimal. Put Nginx or a cloud load balancer in front.
The --forwarded-allow-ips flag matters. If you leave it at the default (127.0.0.1) behind a load balancer on a different IP, request.client.host will show the proxy IP and your rate limiter will see every request as coming from one address. Set it correctly or your rate limiting is fiction.
SBOM Every Build
Generate a CycloneDX or SPDX SBOM at every build, not just at release. The CI overhead is seconds. The benefit is that when a zero-day lands — as happened with the tarfile issue in CPython affecting downstream Python apps — you can query "which services have this" in seconds instead of rebuilding environments by hand.
cyclonedx-py handles Poetry, pip, Pipenv, and venv outputs. Ship the SBOM alongside your Docker image as an attestation, sign it with Cosign, and you have a production-grade supply chain story.
Pre-Production Scans Are Not Enough
I have seen teams run pip-audit once per pull request and declare victory. Then a new CVE lands on a package already in the lock file and nobody notices until the next PR, which might be weeks away. Continuous monitoring — daily scans against the current lock files in every deployed service — is the minimum. The OSV.dev database updates in near-real-time; if your vulnerability tooling polls less frequently than daily, it is giving you stale answers.
Secrets in FastAPI Dependencies
FastAPI's dependency injection is elegant and it encourages putting configuration into dependencies. Depends(get_settings) is fine, but be careful: if your settings object logs itself on startup (via Pydantic's repr), API keys end up in stdout. Pydantic SecretStr exists for this reason. Use it. And make sure your logging filter redacts SecretStr properly — I have seen custom JSON formatters that call str() on the whole model and leak everything.
How Safeguard Helps
Safeguard's reachability analysis cuts the FastAPI CVE noise by tracing which routes and middleware actually touch vulnerable code paths in Starlette or Pydantic, so a multipart parsing bug does not page you if you only expose JSON APIs. Griffin AI reads your FastAPI router layout and dependency graph to propose targeted upgrade PRs, including matching Starlette bumps when FastAPI's pin range shifts. SBOM generation captures the whole ASGI stack — Uvicorn, python-multipart, the plugins — and policy gates can block deploys if the SBOM shows a package with an active critical advisory, or if it detects python-jose still present after your migration deadline.