This document is designed as a **security spec** that supports: 1. **Secure-by-default code generation** for new FastAPI code. 2. **Security review / vulnerability hunting** in existing FastAPI code (passive “notice issues while working” and active “scan the repo and report findings”). It is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them). FastAPI is commonly d...
Installs into .claude/skills of the current project.
Are you the author of 2137 Python Fastapi Web Server Security Bd207b2b?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/tools-only-2137-python-fastapi-web-server-security-bd207b2b)
# FastAPI (Python) Web Security Spec (FastAPI 0.128.x, Python 3.x) ([PyPI][1])
This document is designed as a **security spec** that supports:
1. **Secure-by-default code generation** for new FastAPI code.
2. **Security review / vulnerability hunting** in existing FastAPI code (passive “notice issues while working” and active “scan the repo and report findings”).
It is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).
FastAPI is commonly deployed with an ASGI server (e.g., Uvicorn) and is built on Starlette + Pydantic, so this spec covers those layers where they affect security. ([PyPI][1])
---
## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)
- MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, signing keys, database URLs with credentials).
- MUST NOT “fix” security by disabling protections (e.g., weakening auth, making CORS permissive, skipping signature checks, disabling validation, turning off TLS verification, adding `allow_origins=["*"]` with credentials).
- MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify the claim.
- MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, WAF, CDN, service mesh), report it as “not visible in app code; verify at runtime/config”.
- MUST treat browser controls correctly:
- CORS is **not** an auth mechanism; it only affects browsers.
- CSRF defenses apply when the browser automatically attaches credentials (cookies); they are usually not relevant for purely header-token APIs. ([OWASP Cheat Sheet Series][2])
---
## 1) Operating modes
### 1.1 Generation mode (default)
When asked to write new FastAPI code or modify existing code:
- MUST follow every **MUST** requirement in this spec.
- SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.
- MUST prefer safe-by-default APIs and proven libraries over custom security code.
- MUST avoid introducing new risky sinks (shell execution, unsafe deserialization, dynamic eval, untrusted template rendering, unsafe file serving, unsafe redirects, arbitrary outbound fetching).
### 1.2 Passive review mode (always on while editing)
While working anywhere in a FastAPI repo (even if the user did not ask for a security scan):
- MUST “notice” violations of this spec in touched/nearby code.
- SHOULD mention issues as they come up, with a brief explanation + safe fix.
### 1.3 Active audit mode (explicit scan request)
When the user asks to “scan”, “audit”, or “hunt for vulns”:
- MUST systematically search the codebase for violations of this spec.
- MUST output findings in a structured format (see §2.3).
Recommended audit order:
1. App entrypoints / deployment scripts / Dockerfiles / Procfiles / Helm/terraform.
2. ASGI server configuration (Uvicorn/Gunicorn), proxy settings, debug/reload settings.
3. FastAPI app configuration (docs exposure, middleware, trusted hosts, CORS).
4. Authn/Authz design (dependencies, JWT/session handling, password storage).
5. Cookie/session usage + CSRF (if cookies are used).
6. Input validation and output shaping (Pydantic models, mass assignment, excessive data exposure).
7. Template rendering and XSS/SSTI (if HTML is served).
8. File handling (uploads + downloads), StaticFiles, Range support.
9. Injection classes (SQL, command execution, unsafe deserialization).
10. Outbound requests (SSRF), redirect handling, WebSockets security.
---
## 2) Definitions and review guidance
### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)
Examples include:
- Query parameters / path parameters
- JSON bodies (including nested fields)
- Headers (including `Host`, `Origin`, `X-Forwarded-*`)
- Cookies (including session cookies)
- File uploads (multipart parts)
- WebSocket messages, query params, and headers during handshake ([Starlette][3])
- Any data from external systems (webhooks, third-party APIs, message queues)
- Any persisted user content (DB rows) that originated from users
### 2.2 State-changing request
A request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.
### 2.3 Required audit finding format
For each issue found, output:
- Rule ID:
- Severity: Critical / High / Medium / Low
- Location: file path + function/route name + line(s)
- Evidence: the exact code/config snippet
- Impact: what could go wrong, who can exploit it
- Fix: safe change (prefer minimal diff)
- Mitigation: defense-in-depth if immediate fix is hard
- False positive notes: what to verify if uncertain
---
## 3) Secure baseline: minimum production configuration (MUST in production)
This is the smallest “production baseline” that prevents common FastAPI/ASGI misconfigurations.
Baseline goals:
- No debug tracebacks or auto-reload in production. ([PyPI][4])
- Run under a production ASGI server configuration (workers, timeouts, resource controls). ([PyPI][4])
- Host header validation enabled (TrustedHostMiddleware or equivalent). ([PyPI][5])
- CORS disabled unless explicitly needed; if enabled, it is strict and least-privilege. ([OWASP Cheat Sheet Series][6])
- Auth is enforced consistently via dependencies (no “oops, forgot auth on this route”). ([FastAPI][7])
- If cookies/sessions are used, cookie flags are secure and CSRF is addressed. ([OWASP Cheat Sheet Series][8])
- Request size limits and multipart limits exist at the edge and are validated in app as needed (to mitigate memory/CPU DoS). ([advisories.gitlab.com][9])
- Dependencies are patched promptly, especially Starlette/python-multipart (multiple DoS and traversal advisories exist historically). ([advisories.gitlab.com][10])
---
## 4) Rules (generation + audit)
Each rule contains: required practice, insecure patterns, detection hints, and remediation.
### FASTAPI-DEPLOY-001: Do not use auto-reload / dev-only server modes in production
Severity: High (if production)
Required:
- MUST NOT run production using auto-reload/watch mode (e.g., Uvicorn reload).
- MUST run with a production process model (e.g., multiple workers where appropriate) and stable server settings. ([PyPI][4])
Insecure patterns:
- `uvicorn ... --reload` (or equivalent “reload=True” configs) in production entrypoints.
- Docker/Procfile/systemd commands that run with `--reload` in production.
Detection hints:
- Search for `--reload`, `reload=True`, `watchfiles`, `fastapi dev`, “development” run scripts.
- Check Docker CMD/ENTRYPOINT, Procfile, systemd units, shell scripts.
Fix:
- Remove reload in production; run Uvicorn/Gunicorn with stable settings and explicit worker configuration. ([PyPI][4])
Note:
- Reload is fine for local development. Only flag when it is clearly used as a production entrypoint.
---
### FASTAPI-DEPLOY-002: Debug mode MUST be disabled in production
Severity: Critical
Required:
- MUST NOT enable debug tracebacks in production (FastAPI/Starlette debug mode can expose sensitive internals and make some exploit chains easier). ([PyPI][5])
- MUST treat any configuration that returns detailed stack traces to clients as sensitive.
Insecure patterns:
- `app = FastAPI(debug=True)` (or Starlette `debug=True`), or equivalent environment toggles enabling debug in production. ([PyPI][5])
- Server/log config that exposes tracebacks to end users.
Detection hints:
- Search for `debug=True`, `DEBUG = True`, environment flags mapped to debug.
- Review exception middleware and error handler setup.
Fix:
- Ensure debug is only enabled in local dev/test.
- Return generic error responses to clients; log details internally.
---
### FASTAPI-OPENAPI-001: OpenAPI and interactive docs MUST be disabled or protected in production
Severity: Medium (can be High in sensitive/internal apps)
Required:
- SHOULD disable `/docs`, `/redoc`, and `/openapi.json` in production for public-facing services unless there is an explicit business need.
- If enabled, MUST protect them (e.g., auth, network allowlists, or internal-only routing).
- MUST NOT assume “security through obscurity”; treat docs exposure as an information disclosure amplifier.
Insecure patterns:
- Publicly reachable `/docs` and `/openapi.json` for internal/admin APIs.
- Docs enabled on the same hostname as production without access control.
Detection hints:
- Look for `FastAPI(docs_url=..., redoc_url=..., openapi_url=...)` or defaults.
- Check reverse proxy routing and allowlists.
Fix:
- Disable docs endpoints in prod (`docs_url=None`, `redoc_url=None`, `openapi_url=None`) or restrict access at the edge.
---
### FASTAPI-AUTH-001: Authentication MUST be explicit and consistently enforced via dependencies
Severity: High
Required:
- MUST implement authentication as a dependency (or router-level dependency) so that protected endpoints cannot “forget” auth.
- MUST default to “deny” for privileged routers/endpoints; explicitly mark truly public routes.
- SHOULD centralize auth enforcement at router boundaries (e.g., protected `APIRouter` for authenticated endpoints). ([FastAPI][7])
Insecure patterns:
- Per-route ad-hoc auth checks scattered through handlers (easy to miss).
- A mix of protected/unprotected endpoints with no clear policy.
Detection hints:
- Identify routers and endpoints; check whether protected ones include `Depends(...)`/`Security(...)`.
- Search for patterns like `if user is None: raise ...` inside handlers (instead of dependencies).
Fix:
- Move authentication into a dependency and attach it to the router/endpoint consistently using `Depends()`/`Security()`. ([FastAPI][7])
---
### FASTAPI-AUTH-002: Use standard auth transports; avoid secrets in URLs
Severity: High
Required:
- SHOULD use the `Authorization: Bearer <token>` header for token auth, not query parameters. ([FastAPI][11])
- MUST NOT place secrets (tokens, reset links containing long-lived secrets, API keys) in query strings when avoidable.
Insecure patterns:
- `?token=...`, `?api_key=...`, `?auth=...` used for primary auth.
- Long-lived access tokens embedded in URLs (leak via logs, referrers, caches).
Detection hints:
- Search for parameter names like `token`, `api_key`, `key`, `secret`, `password`.
- Look for security schemes that use query API keys without justification.
Fix:
- Move tokens to Authorization headers; rotate/shorten lifetimes; use POST bodies for sensitive values.
---
### FASTAPI-AUTH-003: Password storage MUST be strongly hashed; never store plaintext passwords
Severity: Critical
Required:
- MUST store passwords using a strong, slow password hashing scheme (e.g., Argon2id, bcrypt).
- MUST NOT store plaintext passwords, or reversible encryption as the primary protection.
- SHOULD use established libraries for hashing and verification (do not roll your own).
Insecure patterns:
- Storing plaintext passwords in DB.
- Using fast hashes (e.g., SHA256) without a proper password hashing KDF.
- Returning password hashes in API responses.
Detection hints:
- Search for `password=` persisted fields, and look for `hashlib.md5/sha1/sha256` usage on passwords.
- Inspect response models for password/hash fields.
Fix:
- Migrate to a proper password hashing library; add a re-hash-on-login upgrade path.
---
### FASTAPI-AUTH-004: JWT validation MUST be strict; JWTs MUST NOT carry secrets
Severity: High
Required:
- MUST validate JWT signature and enforce an algorithm allowlist.
- MUST validate standard claims appropriate to your system (at least `exp`; typically also `iss`/`aud` if multi-service or multi-tenant).
- MUST treat JWT contents as readable by the client; do not put secrets in JWT payloads. ([FastAPI][12])
Insecure patterns:
- `jwt.decode(..., options={"verify_signature": False})` or equivalent.
- Accepting `alg=none` / algorithm confusion.
- Using JWT payload to store sensitive secrets (API keys, passwords).
Detection hints:
- Search for `jwt.decode`, `python-jose`, `PyJWT`, `verify_signature`.
- Check for missing exp validation or long expirations.
Fix:
- Enforce strict validation (signature, allowed algorithms, exp, and any required issuer/audience constraints).
- Store only identifiers/claims you are comfortable exposing to the client. ([FastAPI][12])
---
### FASTAPI-AUTHZ-001: Authorization MUST be enforced per-object and per-property
Severity: High
Required:
- MUST perform object-level authorization whenever accessing a resource by user-controlled identifier (ID in path/query/body).
- MUST perform property-level authorization and response shaping to prevent “excessive data exposure” (e.g., admin-only fields). ([OWASP Foundation][13])
Insecure patterns:
- `GET /users/{id}` returns user record without verifying caller can access that `id`.
- Response models include internal fields (roles, permissions, billing data, password hashes).
Detection hints:
- Enumerate endpoints that accept IDs; trace whether an authz check is performed.
- Compare response models for public vs internal fields.
Fix:
- Add object-level checks (ownership, ACLs, tenant boundaries).
- Use dedicated response models that include only allowed fields.
---
### FASTAPI-SESS-001: If using cookie-based sessions and TLS, cookie attributes MUST be secure in production
Severity: High (only if TLS is enabled)
Required (production, HTTPS):
- MUST set session cookies to be sent only over HTTPS (secure). IMPORTANT NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.
- MUST set HttpOnly for session cookies (not accessible to JS).
- SHOULD use `SameSite=Lax` (or `Strict` if UX allows); if you require cross-site cookies, document the CSRF implications and add compensating controls. ([OWASP Cheat Sheet Series][8])
- If using Starlette `SessionMiddleware`, MUST set `https_only=True` in production and choose an appropriate `same_site`. ([PyPI][5])
Insecure patterns:
- Session cookies without Secure/HttpOnly.
- `SameSite=None` cookies used for authenticated state-changing endpoints without CSRF protections.
Detection hints:
- Search for `SessionMiddleware(` and inspect parameters like `https_only`, `same_site`.
- Search for `set_cookie(` usage and cookie flags.
Fix:
- Set secure cookie attributes; prefer short lifetimes for high-privilege sessions. ([OWASP Cheat Sheet Series][8])
---
### FASTAPI-SESS-002: Do not store sensitive secrets in signed session cookies
Severity: High
Required:
- MUST assume cookie-based session data is readable by the client (signed ≠ encrypted); do not store secrets/PII unless encrypted server-side.
- Store only opaque identifiers (e.g., session ID) or non-sensitive state in the cookie; store sensitive session state server-side. ([OWASP Cheat Sheet Series][8])
Insecure patterns:
- Storing access tokens, refresh tokens, or PII directly in cookie session payloads.
- Treating “signed cookies” as confidential storage.
Detection hints:
- Search for `request.session[...] =` or `session[...] =`-equivalent patterns; identify what is stored.
- Identify use of `SessionMiddleware` or other cookie session mechanisms.
Fix:
- Move sensitive values to server-side storage; keep cookie minimal.
---
### FASTAPI-CSRF-001: Cookie-authenticated state-changing requests MUST be CSRF-protected
Severity: High
Note: This only applies if using cookie based auth. If the application uses header or token based auth such as Authorization header, then CSRF is not an issue.
Required:
- MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.
- SHOULD use a proven CSRF approach (synchronizer token pattern, or well-reviewed middleware) rather than rolling your own. ([OWASP Cheat Sheet Series][2])
- MAY add defense-in-depth (Origin/Referer checks, SameSite cookies, Fetch Metadata), but tokens are the primary defense for cookie-authenticated apps. ([OWASP Cheat Sheet Series][2])
- IMPORTANT NOTE: If cookies are not used for auth (auth is via `Authorization` header), CSRF is usually not applicable. ([FastAPI][11])
Insecure patterns:
- Cookie-authenticated endpoints that change state with no CSRF validation.
- Using GET for state-changing actions (amplifies CSRF risk).
Detection hints:
- Enumerate routes with methods other than GET; identify whether cookies are used for auth.
- Look for CSRF token generation/verification or middleware.
Fix:
- Add CSRF tokens (and validate them) on state-changing actions when cookie auth is in use. ([OWASP Cheat Sheet Series][2])
---
### FASTAPI-VALID-001: Request parsing and validation MUST be schema-driven; prevent mass assignment
Severity: Medium (especially for APIs that write to DB)
Required:
- SHOULD use Pydantic models for request bodies instead of accepting arbitrary `dict`/`Any`.
- SHOULD configure models to reject unexpected fields where appropriate (prevents “mass assignment” style bugs).
- MUST validate and normalize identifiers (IDs, email, URLs) before using them for access control or side effects. ([OWASP Cheat Sheet Series][14])
Insecure patterns:
- `payload = await request.json()` followed by `Model(**payload)` or direct DB writes with `payload` (no allowlist).
- Models that silently accept unknown fields for write endpoints.
Detection hints:
- Search for `await request.json()`, `request.body()`, `dict`-typed bodies, `Any`-typed bodies.
- Look for endpoints that do `db.update(**payload)` or `Model(**payload)` with unfiltered input.
Fix:
- Use explicit Pydantic models with allowlisted fields; reject extras for write endpoints. ([OWASP Cheat Sheet Series][14])
---
### FASTAPI-RESP-001: Prevent excessive data exposure via response models and explicit serialization
Severity: Medium
Required:
- MUST define response models that include only intended fields (especially for user objects, auth-related objects, billing objects).
- SHOULD use separate models for “create input”, “db/internal”, and “public output” to avoid leaking sensitive fields. ([FastAPI][15])
Insecure patterns:
- Returning ORM objects or dicts that include internal columns.
- Reusing “DB model” as the response model (includes `password_hash`, `is_admin`, etc).
Detection hints:
- Look for endpoints that `return user` where `user` is an ORM instance.
- Check for `response_model` omissions on endpoints that return sensitive resources.
Fix:
- Add explicit response models; create “public” schemas that exclude sensitive fields. ([FastAPI][15])
---
### FASTAPI-XSS-001: Prevent reflected/stored XSS in HTML responses and templates
Severity: High (if the service serves HTML)
Required:
- MUST use templating with auto-escaping enabled for HTML.
- MUST NOT mark untrusted content as safe (no unsafe “raw HTML” rendering of user-controlled data).
- SHOULD deploy a CSP when serving HTML that includes any user content. ([OWASP Cheat Sheet Series][16])
Insecure patterns:
- Rendering user content directly into HTML without escaping/sanitization.
- Disabling auto-escaping or using “raw HTML” features without sanitization.
Detection hints:
- Search for template rendering and string concatenation that builds HTML.
- Review templates for “unsafe” filters/constructs and unquoted attributes.
Fix:
- Keep auto-escaping on; sanitize user HTML only if absolutely required using a trusted sanitizer; add CSP. ([OWASP Cheat Sheet Series][16])
Note:
- If the app is a pure JSON API, XSS is usually a client/app concern, but error pages/docs pages might still render HTML.
---
### FASTAPI-SSTI-001: Never render untrusted templates (Server-Side Template Injection)
Severity: Critical
Required:
- MUST NOT render templates that contain user-controlled template syntax.
- MUST treat “template-from-string” rendering as dangerous if influenced by untrusted input.
- If untrusted templates are absolutely required (rare, high-risk):
- MUST use a sandboxed templating approach and restrict capabilities.
- MUST assume sandbox escapes are possible; add isolation and strict allowlists. ([OWASP Foundation][17])
Insecure patterns:
- Rendering templates loaded from user input or DB via a normal Jinja environment.
- Building templates dynamically using user-controlled strings.
Detection hints:
- Grep for Jinja `Environment.from_string`, `Template(...)`, or similar.
- Trace origin of template string (request, DB, uploads, admin panels).
Fix:
- Replace with non-executable templating (simple string substitution).
- If truly needed, use Jinja’s sandbox environment plus strong isolation. ([jinja.palletsprojects.com][18])
---
### FASTAPI-HEADERS-001: Set essential security headers (in app or at the edge)
Severity: Medium
Required (typical API/web app):
- SHOULD set:
- `X-Content-Type-Options: nosniff`
- Clickjacking protection (`X-Frame-Options` and/or CSP `frame-ancestors`) if HTML is served
- `Referrer-Policy` and `Permissions-Policy` as appropriate
NOTE:
- Headers may be set by a proxy/CDN. If not visible in app code, flag as “verify at edge”. ([OWASP Cheat Sheet Series][6])
Insecure patterns:
- No security headers anywhere (app or edge) for apps serving HTML or sensitive APIs.
Detection hints:
- Search for middleware that sets headers; check reverse proxy config.
Fix:
- Set headers centrally (middleware) or via reverse proxy/CDN.
---
### FASTAPI-CORS-001: CORS MUST be explicit and least-privilege
Severity: Medium (High if misconfigured with credentials)
Required:
- If CORS is not needed, MUST keep it disabled.
- If CORS is needed:
- MUST allowlist trusted origins (do not reflect arbitrary origins).
- MUST NOT combine credentialed requests with wildcard origins (this is unsafe and commonly rejected by compliant middleware). ([OWASP Cheat Sheet Series][6])
- SHOULD restrict allowed methods and headers.
Insecure patterns:
- `allow_origins=["*"]` together with `allow_credentials=True`.
- Reflecting `Origin` without validation.
- `allow_origin_regex=".*"` used broadly.
Detection hints:
- Search for `CORSMiddleware` configuration.
- Look for `allow_origins=["*"]`, `allow_credentials=True`, `allow_origin_regex`.
Fix:
- Use an explicit origin allowlist and minimal methods/headers; keep credentials off unless required. ([OWASP Cheat Sheet Series][6])
---
### FASTAPI-HOST-001: Host header MUST be validated in production
Severity: Low
Required:
- SHOULD use `TrustedHostMiddleware` (or equivalent at edge) to restrict accepted Host values. ([PyPI][5])
- MUST NOT trust the `Host` header for security-sensitive decisions without validation.
Insecure patterns:
- No Host validation while generating external URLs (password reset links, callback URLs) from request host.
- Allowing arbitrary Host headers in apps behind permissive proxies.
Detection hints:
- Search for `TrustedHostMiddleware` usage.
- Search for logic that uses `request.url`, `request.base_url`, or host-derived values to build external URLs.
Fix:
- Configure a strict allowed-hosts list in production; enforce at edge too if possible.
---
### FASTAPI-PROXY-001: Reverse proxy trust MUST be configured correctly
Severity: High (when behind a proxy)
Required:
- If behind a reverse proxy, MUST configure forwarded-header trust correctly.
- MUST NOT blindly trust `X-Forwarded-*` headers from the open internet.
- If using Uvicorn proxy header support, MUST restrict which IPs are allowed to provide forwarded headers. ([PyPI][4])
Insecure patterns:
- Enabling proxy headers broadly without restricting trusted proxy IPs.
- Using forwarded headers to decide “is secure” / “is internal” / “client IP” without proper trust boundaries.
Detection hints:
- Search for `--proxy-headers`, `--forwarded-allow-ips`, or equivalent config.
- Search for security-sensitive use of `request.client.host`, `request.url.scheme`, `request.headers["x-forwarded-for"]`.
Fix:
- Configure Uvicorn with proxy headers only when behind a known proxy, and restrict `forwarded_allow_ips` to that proxy. ([PyPI][4])
- Keep Host allowlisting in place even behind proxies.
---
### FASTAPI-LIMITS-001: Request and multipart limits MUST be enforced to prevent DoS
Severity: Low
Required:
- MUST enforce request size limits at the edge (reverse proxy/load balancer) and validate in app where needed.
- MUST apply special scrutiny to multipart/form-data handling; historical vulnerabilities include unbounded buffering and DoS vectors. ([advisories.gitlab.com][9])
- SHOULD rate limit and/or add per-IP/per-user throttles for expensive endpoints.
Insecure patterns:
- Accepting arbitrarily large JSON bodies or multipart forms.
- Parsing multipart forms without size/field-count controls.
Detection hints:
- Identify file upload endpoints and `multipart/form-data` usage.
- Look for missing proxy-level limits (nginx `client_max_body_size`, ALB limits, etc.) and missing app-level checks.
Fix:
- Enforce strict body limits and multipart constraints; keep Starlette and python-multipart updated to patched versions. ([advisories.gitlab.com][9])
---
### FASTAPI-FILES-001: Prevent path traversal and unsafe static file exposure
Severity: High
Required:
- MUST NOT pass user-controlled file paths to `FileResponse`/filesystem calls without strict validation and safe base directories.
- If using `StaticFiles`, MUST keep Starlette updated and understand the security history (path traversal advisory exists for older versions). ([advisories.gitlab.com][10])
- MUST NOT serve user uploads as executable/active content (especially HTML/JS) from a static root without safe handling.
Insecure patterns:
- `FileResponse(request.query_params["path"])`
- Mounting `StaticFiles(directory="uploads")` where uploads include HTML/JS/SVG and are served inline.
Detection hints:
- Search for `FileResponse(`, `StaticFiles(`, `open(` in routes.
- Trace whether the path originates from untrusted input.
Fix:
- Use opaque IDs for files; map IDs to server-side stored paths.
- Serve untrusted content as attachment downloads where appropriate.
---
### FASTAPI-FILES-002: Mitigate Range-header DoS on file-serving endpoints
Severity: Low (if affected versions and file serving is enabled)
Required:
- MUST keep Starlette patched against known file-serving DoS issues if using `FileResponse`/`StaticFiles`.
- MUST treat unusual `Range` header handling and file serving as a DoS surface. ([advisories.gitlab.com][19])
Insecure patterns:
- Serving large files with vulnerable Starlette versions.
- No rate limiting / CDN shielding for file endpoints.
Detection hints:
- Identify Starlette version; if in affected range, flag.
- Find uses of `FileResponse` and `StaticFiles`.
Fix:
- Upgrade Starlette to a fixed version per advisory guidance. ([advisories.gitlab.com][19])
- Add edge caching/rate limiting for file endpoints where appropriate.
---
### FASTAPI-UPLOAD-001: File uploads MUST be validated, stored safely, and served safely
Severity: Medium
Required:
- MUST enforce upload size limits (app + edge).
- MUST validate file type using allowlists and content checks (not only extension). ([OWASP Cheat Sheet Series][20])
- SHOULD generate server-side filenames (random IDs) and avoid trusting original names.
- MUST serve potentially active formats safely (download attachment) unless explicitly intended.
Insecure patterns:
- Accepting arbitrary file types and serving them back inline.
- Using user-supplied filename as storage path.
Detection hints:
- Look for upload handlers and where/how files are written.
- Look for direct exposure of upload directories.
Fix:
- Implement allowlist validation + safe storage + safe serving; add scanning/quarantine if applicable. ([OWASP Cheat Sheet Series][20])
---
### FASTAPI-INJECT-001: Prevent SQL injection (use parameterized queries / ORM)
Severity: High
Required:
- MUST use parameterized queries or an ORM that parameterizes under the hood.
- MUST NOT build SQL by string concatenation / f-strings with untrusted input. ([OWASP Cheat Sheet Series][21])
Insecure patterns:
- `f"SELECT ... WHERE id={user_id}"`
- `"... WHERE name = '%s'" % user_input`
Detection hints:
- Grep for SQL keywords in Python strings near `.execute(...)`.
- Trace untrusted data into DB calls.
Fix:
- Replace with parameterized queries / ORM query APIs; validate types before querying. ([OWASP Cheat Sheet Series][21])
---
### FASTAPI-INJECT-002: Prevent OS command injection
Severity: Critical to High (depends on exposure)
Required:
- MUST avoid executing shell commands with untrusted input.
- If subprocess is necessary:
- MUST pass args as a list (not a string)
- MUST NOT use `shell=True` with attacker-influenced strings
- SHOULD use strict allowlists for any variable component ([OWASP Cheat Sheet Series][22])
Insecure patterns:
- `os.system(user_input)`
- `subprocess.run(f"cmd {user}", shell=True)`
- Passing user strings into `bash -c`, `sh -c`, PowerShell, etc.
Detection hints:
- Search for `os.system`, `subprocess`, `Popen`, `shell=True`.
- Trace data from request/DB into these calls.
Fix:
- Use library APIs instead of shell commands.
- If unavoidable, hard-code the command and allowlist validated parameters; use `--` separator where supported. ([OWASP Cheat Sheet Series][22])
---
### FASTAPI-SSRF-001: Prevent server-side request forgery (SSRF) in outbound HTTP
Severity: Medium (can be High in cloud/VPC environments)
- Note: For small stand alone projects this is less important. It is most important when deploying into an LAN or with other services listening on the same server.
Required:
- MUST treat outbound requests to user-provided URLs as high risk.
- SHOULD validate and restrict destinations (allowlist hosts/domains) for any user-influenced URL fetch.
- SHOULD block access to localhost/private IP ranges/link-local and cloud metadata endpoints.
- MUST restrict protocols to http/https.
- SHOULD set timeouts and carefully control redirects. ([OWASP Cheat Sheet Series][23])
Insecure patterns:
- `httpx.get(request.query_params["url"])`
- “URL preview/import/webhook tester” features that accept arbitrary URLs.
Detection hints:
- Search for `requests`, `httpx`, `urllib`, `aiohttp` calls with URLs derived from requests/DB.
- Identify endpoints named `fetch`, `preview`, `proxy`, `webhook`, `import`.
Fix:
- Implement strict URL parsing + allowlists; add egress controls; set short timeouts; disable redirects if not required. ([OWASP Cheat Sheet Series][23])
---
### FASTAPI-REDIRECT-001: Prevent open redirects
Severity: Low
Required:
- MUST validate redirect targets derived from untrusted input (`next`, `redirect`, `return_to`).
- SHOULD prefer redirecting only to same-site relative paths or an allowlist of domains. ([OWASP Cheat Sheet Series][24])
Insecure patterns:
- Returning `RedirectResponse(next)` where `next` is user-controlled with no validation.
Detection hints:
- Search for `RedirectResponse(` or redirect logic and examine the source of the target.
Fix:
- Allow only relative paths or allowlisted domains; fall back to a safe default. ([OWASP Cheat Sheet Series][24])
---
### FASTAPI-WS-001: WebSocket endpoints MUST be authenticated and protected against cross-site abuse
Severity: Medium to High (depends on data/privilege)
Required:
- MUST authenticate WebSocket connections for any non-public channel (WebSockets don’t inherently provide auth). ([OWASP Cheat Sheet Series][25])
- SHOULD enforce origin/CSRF-like protections appropriate for browser-based WebSocket clients (Origin validation is a common control).
- SHOULD rate limit message frequency and connection attempts; close idle/abusive connections.
Insecure patterns:
- `@app.websocket(...)` accepts and trusts the connection with no auth check.
- Using query-string tokens for auth without considering leakage/rotation.
Detection hints:
- Search for `@app.websocket` / `websocket_endpoint` and inspect whether auth is performed before accepting sensitive operations.
- Review origin checks, token parsing, and per-connection authorization.
Fix:
- Require authentication during handshake (e.g., a token or session) and enforce authorization for actions/messages.
- Validate Origin for browser-based clients where appropriate; apply rate limits and timeouts. ([OWASP Cheat Sheet Series][25])
---
### FASTAPI-SUPPLY-001: Dependency and patch hygiene (focus on security-relevant deps)
Severity: Low
Required:
- SHOULD pin and regularly update security-critical dependencies (FastAPI, Starlette, Uvicorn, Pydantic, python-multipart, auth/JWT libs).
- MUST respond to known security advisories promptly.
- MUST treat file serving and multipart parsing dependencies as security-sensitive due to historical CVEs. ([advisories.gitlab.com][10])
Audit focus examples (historical):
- Starlette StaticFiles path traversal (fixed in 0.27.0). ([advisories.gitlab.com][10])
- Starlette multipart/form-data DoS (fixed in 0.40.0). ([advisories.gitlab.com][9])
- Starlette FileResponse Range header DoS (fixed in 0.49.1). ([advisories.gitlab.com][19])
Detection hints:
- Check `requirements.txt`, lockfiles, container images, and runtime environments for actual installed versions.
- Map file upload/file serving features to dependency versions.
Fix:
- Upgrade to patched versions per advisories; add regression tests around affected behavior.
---
## 5) Practical scanning heuristics (how to “hunt”)
When actively scanning, use these high-signal patterns:
- Dev server / debug:
- `--reload`, `reload=True`, `debug=True`, `FastAPI(debug=True)` ([PyPI][4])
- OpenAPI/docs exposure:
- `/docs`, `/redoc`, `/openapi.json`, `docs_url=`, `openapi_url=`
- Auth enforcement gaps:
- Endpoints missing `Depends()`/`Security()` where expected; routers without a consistent dependency boundary ([FastAPI][7])
- Tokens in query params (`token=`, `api_key=`, `key=`) ([FastAPI][11])
- Session/cookies + CSRF:
- `SessionMiddleware(` and cookie flags (`https_only`, `same_site`) ([PyPI][5])
- POST/PUT/PATCH/DELETE handlers using cookie auth with no CSRF checks ([OWASP Cheat Sheet Series][2])
- Input validation & mass assignment:
- `await request.json()` and direct DB writes from dicts; models accepting extra fields ([OWASP Cheat Sheet Series][14])
- Excessive data exposure:
- Returning ORM objects or dicts without `response_model`; responses containing password/role/internal fields ([FastAPI][15])
- CORS:
- `CORSMiddleware` with `allow_origins=["*"]`, `allow_origin_regex=".*"`, `allow_credentials=True` ([OWASP Cheat Sheet Series][6])
- Files:
- `FileResponse(` with user-controlled paths; `StaticFiles(` exposing uploads ([advisories.gitlab.com][10])
- Uploads / multipart:
- `multipart/form-data` endpoints with no size/field constraints; outdated Starlette/python-multipart ([advisories.gitlab.com][9])
- Injection:
- SQL strings with f-strings/concatenation into `.execute(...)` ([OWASP Cheat Sheet Series][21])
- `subprocess.*`, `shell=True`, `os.system` ([OWASP Cheat Sheet Series][22])
- SSRF:
- `httpx.get/post` or `requests.*` with URL from request/DB, no allowlist/timeouts ([OWASP Cheat Sheet Series][23])
- Redirect:
- `RedirectResponse(next)` with no validation ([OWASP Cheat Sheet Series][24])
- WebSockets:
- `@app.websocket` handlers without auth/origin checks; use of `ws://` in prod configs ([FastAPI][27])
Always try to confirm:
- data origin (untrusted vs trusted)
- sink type (SQL/subprocess/files/template/http/redirect/ws)
- protective controls present (validation, allowlists, middleware, edge controls)
- installed dependency versions vs vulnerable ranges ([advisories.gitlab.com][10])
---
## 6) Sources (accessed 2026-01-27)
Primary framework documentation:
- FastAPI (PyPI metadata, versioning) — `https://pypi.org/project/fastapi/` ([PyPI][1])
- FastAPI docs: Security “First Steps” (Authorization Bearer header conventions) — `https://fastapi.tiangolo.com/tutorial/security/first-steps/` ([FastAPI][11])
- FastAPI reference: Dependencies (`Depends`, `Security`) — `https://fastapi.tiangolo.com/reference/dependencies/` ([FastAPI][7])
- FastAPI reference: APIRouter (router-level dependencies) — `https://fastapi.tiangolo.com/reference/apirouter/` ([FastAPI][28])
- FastAPI docs: WebSockets — `https://fastapi.tiangolo.com/advanced/websockets/` ([FastAPI][27])
ASGI/server stack documentation:
- Starlette (PyPI, general capabilities) — `https://pypi.org/project/starlette/` ([PyPI][5])
- Starlette docs: WebSockets — `https://starlette.dev/websockets/` ([Starlette][3])
- Uvicorn (PyPI metadata) — `https://pypi.org/project/uvicorn/` ([PyPI][4])
- Pydantic docs (v2.12.x) — `https://docs.pydantic.dev/latest/` ([Pydantic][29])
Security standards and cheat sheets:
- OWASP Cheat Sheet Series: Session Management — `https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][8])
- OWASP Cheat Sheet Series: CSRF Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][2])
- OWASP Cheat Sheet Series: XSS Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][16])
- OWASP Cheat Sheet Series: Mass Assignment — `https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][14])
- OWASP API Security Top 10 (2023) — `https://owasp.org/API-Security/editions/2023/en/0x11-t10/` ([OWASP Foundation][13])
- OWASP Cheat Sheet Series: SQL Injection Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][21])
- OWASP Cheat Sheet Series: OS Command Injection Defense — `https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][22])
- OWASP Cheat Sheet Series: SSRF Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][23])
- OWASP Cheat Sheet Series: File Upload — `https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][20])
- OWASP Cheat Sheet Series: Unvalidated Redirects and Forwards — `https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][24])
- OWASP Cheat Sheet Series: HTTP Security Response Headers — `https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][6])
- OWASP Cheat Sheet Series: WebSocket Security — `https://cheatsheetseries.owasp.org/cheatsheets/WebSocket_Security_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][25])
- OWASP WSTG: Testing for Server-Side Template Injection — `https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/07-Input_Validation_Testing/18-Testing_for_Server_Side_Template_Injection` ([OWASP Foundation][17])
- OWASP WSTG: Testing WebSockets — `https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client-side_Testing/10-Testing_WebSockets` ([OWASP Foundation][26])
Template safety references:
- Jinja: Sandbox — `https://jinja.palletsprojects.com/en/stable/sandbox/` ([jinja.palletsprojects.com][18])
Selected supply-chain/advisory references (Starlette examples):
- CVE-2023-29159 (StaticFiles path traversal; fixed 0.27.0) — `https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2023-29159/` ([advisories.gitlab.com][10])
- CVE-2024-47874 (multipart/form-data DoS; fixed 0.40.0) — `https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2024-47874/` ([advisories.gitlab.com][9])
- CVE-2025-62727 (FileResponse Range header DoS; fixed 0.49.1) — `https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2025-62727/` ([advisories.gitlab.com][19])
[1]: https://pypi.org/project/fastapi/ 'https://pypi.org/project/fastapi/'
[2]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html 'https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html'
[3]: https://starlette.dev/websockets/ 'Websockets'
[4]: https://pypi.org/project/uvicorn/ 'https://pypi.org/project/uvicorn/'
[5]: https://pypi.org/project/starlette/ 'https://pypi.org/project/starlette/'
[6]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html 'HTTP Security Response Headers Cheat Sheet'
[7]: https://fastapi.tiangolo.com/reference/dependencies/ 'Dependencies - Depends() and Security() - FastAPI'
[8]: https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html 'https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html'
[9]: https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2024-47874/ 'Starlette Denial of service (DoS) via multipart/form-data | GitLab Advisory Database'
[10]: https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2023-29159/ 'Starlette has Path Traversal vulnerability in StaticFiles | GitLab Advisory Database'
[11]: https://fastapi.tiangolo.com/tutorial/security/first-steps/ 'Security - First Steps - FastAPI'
[12]: https://fastapi.tiangolo.com/tutorial/response-model/ 'https://fastapi.tiangolo.com/tutorial/response-model/'
[13]: https://owasp.org/API-Security/editions/2023/en/0x11-t10/ 'https://owasp.org/API-Security/editions/2023/en/0x11-t10/'
[14]: https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html 'https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html'
[15]: https://fastapi.tiangolo.com/tutorial/extra-models/ 'https://fastapi.tiangolo.com/tutorial/extra-models/'
[16]: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html 'https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html'
[17]: https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/07-Input_Validation_Testing/18-Testing_for_Server_Side_Template_Injection 'Testing for Server Side Template Injection'
[18]: https://jinja.palletsprojects.com/en/stable/sandbox/ 'Sandbox — Jinja Documentation (3.1.x)'
[19]: https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2025-62727/ 'Starlette vulnerable to O(n^2) DoS via Range header merging in ``starlette.responses.FileResponse`` | GitLab Advisory Database'
[20]: https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html 'https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html'
[21]: https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html 'https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html'
[22]: https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html 'https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html'
[23]: https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html 'https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html'
[24]: https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html 'Unvalidated Redirects and Forwards Cheat Sheet'
[25]: https://cheatsheetseries.owasp.org/cheatsheets/WebSocket_Security_Cheat_Sheet.html 'WebSocket Security - OWASP Cheat Sheet Series'
[26]: https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client-side_Testing/10-Testing_WebSockets 'WSTG - Latest | OWASP Foundation'
[27]: https://fastapi.tiangolo.com/advanced/websockets/ 'WebSockets - FastAPI'
[28]: https://fastapi.tiangolo.com/reference/apirouter/ 'APIRouter class - FastAPI'
[29]: https://docs.pydantic.dev/latest/ 'https://docs.pydantic.dev/latest/'