Skip to main content

A hardened replacement layer for Flask with automatic security defaults. Independent of Microsoft Presidio (a data-anonymization toolkit).

Project description

presidio-hardened-flask

CI CodeQL Python 3.9+ License: MIT

A hardened drop-in replacement for Flask that automatically applies production-grade security defaults (v0.2.0). Change one import line and your existing Flask app gets security headers, rate limiting, CSRF protection (no weak defaults), secret redaction (sink-enforced), input sanitization, and more.

v0.2.0 Security Updates

  • Sink redaction now enforced at the logging sink (RedactingFilter on app.logger).
  • CSRF no longer accepts the dangerous built-in "presidio-dev-key" fallback — requires a strong SECRET_KEY (raises clear error otherwise).
  • pip-audit integrated in dev dependencies and CI.
  • All major audit findings from third-party review remediated; docs (SECURITY, PRESIDIO-REQ, README) updated to match implemented behavior.

Quick Start

Install

pip install presidio-hardened-flask

Usage — Change One Import

Before (plain Flask):

from flask import Flask, jsonify, request

app = Flask(__name__)

@app.route("/")
def index():
    return "Hello, world!"

After (presidio-hardened-flask):

from presidio_flask import Flask, jsonify, request

app = Flask(__name__)

@app.route("/")
def index():
    return "Hello, secure world!"

That's it. Your app now automatically receives:

Feature What It Does (v0.2.0)
Security Headers CSP, HSTS, X-Frame-Options, Permissions-Policy, and more on every response
Rate Limiting 60 req/min per IP with exponential backoff (configurable)
CSRF Protection Sec-Fetch-Site aware + token-based fallback (v0.2: requires strong SECRET_KEY; no 'presidio-dev-key' fallback)
Secret Redaction Passwords, API keys, tokens redacted in before_request logs + sink-level RedactingFilter on app.logger for all records
Session Hardening Secure, HttpOnly, SameSite=Lax cookies by default
Input Sanitization Blocks SQL injection, XSS, and path traversal attempts (abort 400)
CVE Quick-Check Warns at startup + pip-audit in [dev] and CI (v0.2)
Security Logging Structured Presidio event logging (with automatic sink redaction)

Side-by-Side Comparison

Security Headers

Plain Flask returns no security headers by default:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8

presidio-hardened-flask adds them automatically:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Permissions-Policy: geolocation=(), camera=(), microphone=()
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Resource-Policy: same-origin

Rate Limiting

Plain Flask has no built-in rate limiting. A single client can hammer your API.

presidio-hardened-flask enforces per-IP rate limits with informative headers:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 57

When exceeded, returns 429 Too Many Requests with exponential backoff.

Secret Redaction

Plain Flask will happily log passwords and tokens in plain text:

app.logger.info("Request: %s", request.json)
# {"username": "alice", "password": "hunter2", "api_key": "sk-live-abc123"}

presidio-hardened-flask automatically redacts sensitive fields:

from presidio_flask import redact_dict
print(redact_dict({"password": "hunter2", "api_key": "sk-123"}))
# {"password": "***REDACTED***", "api_key": "***REDACTED***"}

CSRF Protection

Plain Flask has no CSRF protection.

presidio-hardened-flask uses a modern two-layer approach:

  1. Sec-Fetch-Site header — blocks cross-origin mutating requests automatically
  2. Token-based fallback — for older browsers or custom setups
from presidio_flask import generate_csrf_token

# In your template / API response:
token = generate_csrf_token()
# Include as X-CSRF-Token header or _csrf_token form field

Configuration

All features are enabled by default but fully configurable:

app = Flask(__name__)
app.config.update(
    # Rate limiting
    PRESIDIO_RATE_LIMIT=100,           # requests per window (default: 60)
    PRESIDIO_RATE_WINDOW=120,          # window in seconds (default: 60)
    PRESIDIO_RATE_LIMIT_ENABLED=True,  # disable entirely if False

    # CSRF
    PRESIDIO_CSRF_ENABLED=True,

    # Input sanitization
    PRESIDIO_SANITIZE_ENABLED=True,

    # Secret redaction
    PRESIDIO_REDACTION_ENABLED=True,

    # Security logging
    PRESIDIO_LOGGING_ENABLED=True,

    # CVE check on startup
    PRESIDIO_CVE_CHECK=True,

    # Custom security headers (merge with/override defaults)
    PRESIDIO_SECURITY_HEADERS={
        "X-Frame-Options": "SAMEORIGIN",
        "Content-Security-Policy": "default-src 'self'; img-src *",
    },
)

Development

# Clone and install
git clone https://github.com/presidio-v/presidio-hardened-flask.git
cd presidio-hardened-flask
uv venv .venv && source .venv/bin/activate
uv pip install -e ".[dev]"

# Run tests
pytest --cov=presidio_flask

# Lint and format
ruff format .
ruff check . --fix

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

presidio_hardened_flask-0.2.0.tar.gz (65.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

presidio_hardened_flask-0.2.0-py3-none-any.whl (13.9 kB view details)

Uploaded Python 3

File details

Details for the file presidio_hardened_flask-0.2.0.tar.gz.

File metadata

  • Download URL: presidio_hardened_flask-0.2.0.tar.gz
  • Upload date:
  • Size: 65.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for presidio_hardened_flask-0.2.0.tar.gz
Algorithm Hash digest
SHA256 cea38940d3dc37d5aa94024c1d0d6594fddb82de704cb34353875bbc21e7c9eb
MD5 6c7b30dc36e5f3f95c1fcd29e43da888
BLAKE2b-256 5cc6b4980cdb85f9730e46141c7fc3ac8532a06426a0a42a848b429999690e95

See more details on using hashes here.

Provenance

The following attestation bundles were made for presidio_hardened_flask-0.2.0.tar.gz:

Publisher: publish.yml on presidio-v/presidio-hardened-flask

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file presidio_hardened_flask-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for presidio_hardened_flask-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ba99c58beb4258c864c29b0e6477878c5e3a10dfea121962532f054d419278c1
MD5 0f3fbffc71949d42299698331203e62e
BLAKE2b-256 472752e137dc5dcb833604489bdb1967de7f884b7c1470c66052a2b59ac9c7a8

See more details on using hashes here.

Provenance

The following attestation bundles were made for presidio_hardened_flask-0.2.0-py3-none-any.whl:

Publisher: publish.yml on presidio-v/presidio-hardened-flask

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page