Skip to main content

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

Metadata

Release files for presidio-hardened-flask 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for presidio-hardened-flask 0.2.0
File Size Uploaded Provenance Actions
presidio_hardened_flask-0.2.0.tar.gz 65.2 kB With provenance Details for presidio_hardened_flask-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for presidio-hardened-flask 0.2.0
File Interpreter ABI Platform Actions
presidio_hardened_flask-0.2.0-py3-none-any.whl Python 3 none any Details for presidio_hardened_flask-0.2.0-py3-none-any.whl

Total release size: 79.2 kB

Release files / presidio_hardened_flask-0.2.0.tar.gz

Download URL presidio_hardened_flask-0.2.0.tar.gz
Size 65.2 kB
Tags Source
SHA-256 checksum
How to use checksums
cea38940d3dc37d5aa94024c1d0d6594fddb82de704cb34353875bbc21e7c9eb
BLAKE2b-256 checksum
How to use checksums
5cc6b4980cdb85f9730e46141c7fc3ac8532a06426a0a42a848b429999690e95
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 11, 2026.

Transparency log

Release files / presidio_hardened_flask-0.2.0-py3-none-any.whl

Download URL presidio_hardened_flask-0.2.0-py3-none-any.whl
Size 13.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ba99c58beb4258c864c29b0e6477878c5e3a10dfea121962532f054d419278c1
BLAKE2b-256 checksum
How to use checksums
472752e137dc5dcb833604489bdb1967de7f884b7c1470c66052a2b59ac9c7a8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 11, 2026.

Transparency log

Security for presidio-hardened-flask 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for presidio_hardened_flask-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 11, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page