A hardened, near drop-in replacement for FastAPI with strong security defaults. Independent of Microsoft Presidio (a data-anonymization toolkit).
Project description
presidio-hardened-fastapi
A hardened, near drop-in replacement for FastAPI with strong security defaults.
Version 0.2.0 — MIT License (v0.2 adds sink redaction, pip-audit in CI/dev, doc alignment)
Quick Start
pip install presidio-hardened-fastapi
# Just swap the import — your existing FastAPI code gains security defaults.
from presidio_fastapi import FastAPI, APIRouter
app = FastAPI(title="My Secure API")
@app.get("/")
async def root():
return {"status": "hardened"}
v0.2.0 Changes
- Sink-level secret redaction via RedactingFilter (automatic for the logger).
- pip-audit integrated in dev extras and CI.
- Docs updated for accuracy (redaction/validation are strong helpers; use them explicitly on input).
- Version and dependency improvements.
What You Get (Automatically)
| Security Feature | Plain FastAPI | presidio-hardened-fastapi |
|---|---|---|
| CORS | Wide open by default | Locked down — no origins allowed unless configured |
| Rate Limiting | None | 60 req/min per IP with exponential backoff (configurable) |
| Security Headers | None | CSP, HSTS, X-Frame-Options, X-Content-Type-Options, etc. |
| Secret Redaction | None | Helpers + automatic sink-level RedactingFilter on presidio_fastapi logs (v0.2) |
| OWASP Validation | Pydantic only | SQL injection, XSS, path traversal checks (opt-in helper: call check_owasp()) |
| Dependency Check | None | On-startup + pip-audit in [dev]/CI (v0.2) |
| Security Logging | None | Structured security event logs (with sink redaction) |
Side-by-Side Comparison
Plain FastAPI
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# You must manually add CORS...
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # dangerous!
allow_methods=["*"],
allow_headers=["*"],
)
# No rate limiting
# No security headers
# No input validation beyond Pydantic
# No secret redaction
@app.post("/login")
async def login(data: dict):
return {"token": "sk-live-abc123secret"} # leaked!
presidio-hardened-fastapi
from presidio_fastapi import FastAPI, Request, check_owasp, redact_dict
app = FastAPI(
title="My Secure API",
cors_allow_origins=["https://myapp.com"], # explicit allowlist
)
@app.post("/login")
async def login(request: Request):
body = await request.json()
check_owasp(body) # blocks SQL injection, XSS, path traversal
# Process login...
response_data = {"token": "sk-live-abc123secret"}
return redact_dict(response_data) # token is redacted in response
Automatic protections applied with zero extra code (v0.2):
- Strict CORS (only
https://myapp.com) - Rate limiting (60 req/min per IP)
- Security headers (CSP, HSTS, X-Frame-Options, ...)
- Sink redaction on all presidio_fastapi logs
- Startup dependency audit (plus pip-audit available)
- Security event logging
Note: check_owasp() and redact_* are powerful helpers — call them on untrusted input/response data for full effect (validation/redaction of bodies is not fully automatic to avoid breaking existing Pydantic models).
Configuration
from presidio_fastapi import FastAPI
app = FastAPI(
cors_allow_origins=["https://trusted.com"],
cors_allow_methods=["GET", "POST"],
cors_allow_headers=["Authorization"],
cors_allow_credentials=True,
enable_rate_limiting=True,
enable_owasp_validation=True,
enable_dep_check=True,
security_headers={
"Content-Security-Policy": "default-src 'self' https://cdn.example.com",
},
)
Per-Route Rate Limiting
from presidio_fastapi import FastAPI, Request
from presidio_fastapi import limiter
app = FastAPI()
@app.get("/expensive")
@limiter.limit("5/minute")
async def expensive_endpoint(request: Request):
return {"data": "rate-limited to 5/min"}
Redaction Utilities
from presidio_fastapi import redact_dict, redact_value
data = {"user": "alice", "api_key": "sk-live-xxxxxxxxxxxx"}
safe = redact_dict(data)
# {"user": "alice", "api_key": "***REDACTED***"}
OWASP Input Validation
from presidio_fastapi import check_owasp, HTTPException
try:
check_owasp({"query": "'; DROP TABLE users;--"})
except HTTPException as e:
print(e.detail) # "Potential SQL injection detected"
Development
git clone https://github.com/presidio-v/presidio-hardened-fastapi
cd presidio-hardened-fastapi
uv venv .venv && source .venv/bin/activate
uv pip install -e ".[dev]"
# Run tests
pytest --cov=presidio_fastapi
# Lint & format
ruff format .
ruff check . --fix
Security
See SECURITY.md for the security policy and vulnerability reporting instructions.
License
MIT — see LICENSE for details.
SDLC
This repository is developed under the Presidio hardened-family SDLC: https://github.com/presidio-v/presidio-hardened-docs/blob/main/sdlc/sdlc-report.md.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file presidio_hardened_fastapi-0.2.0.tar.gz.
File metadata
- Download URL: presidio_hardened_fastapi-0.2.0.tar.gz
- Upload date:
- Size: 51.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9559eeef7fe402bc91400cd13d39259615014ccde69f8a87acb2565b94e0aeea
|
|
| MD5 |
aee04628768ce1da5fce770bb9e29e06
|
|
| BLAKE2b-256 |
6ca6c0495ecf3d123d64033d4a642c884b23fe6ec32dcb36f423319c2b37b4ea
|
Provenance
The following attestation bundles were made for presidio_hardened_fastapi-0.2.0.tar.gz:
Publisher:
publish.yml on presidio-v/presidio-hardened-fastapi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
presidio_hardened_fastapi-0.2.0.tar.gz -
Subject digest:
9559eeef7fe402bc91400cd13d39259615014ccde69f8a87acb2565b94e0aeea - Sigstore transparency entry: 1791551364
- Sigstore integration time:
-
Permalink:
presidio-v/presidio-hardened-fastapi@a9284af018f7d21d68f4fdb109d99e8759b4a738 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/presidio-v
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a9284af018f7d21d68f4fdb109d99e8759b4a738 -
Trigger Event:
push
-
Statement type:
File details
Details for the file presidio_hardened_fastapi-0.2.0-py3-none-any.whl.
File metadata
- Download URL: presidio_hardened_fastapi-0.2.0-py3-none-any.whl
- Upload date:
- Size: 11.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aed87c896e5bd12534b0f0e443bb3644445950413413db983de4a42c9d496dd1
|
|
| MD5 |
1effa2f823f3c52f661ab4d3c14b19d4
|
|
| BLAKE2b-256 |
df5be76d85eda26016a9461c14ae126539e205bc0b5f0a05a87fbceb0a258b2d
|
Provenance
The following attestation bundles were made for presidio_hardened_fastapi-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on presidio-v/presidio-hardened-fastapi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
presidio_hardened_fastapi-0.2.0-py3-none-any.whl -
Subject digest:
aed87c896e5bd12534b0f0e443bb3644445950413413db983de4a42c9d496dd1 - Sigstore transparency entry: 1791551682
- Sigstore integration time:
-
Permalink:
presidio-v/presidio-hardened-fastapi@a9284af018f7d21d68f4fdb109d99e8759b4a738 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/presidio-v
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a9284af018f7d21d68f4fdb109d99e8759b4a738 -
Trigger Event:
push
-
Statement type: