Changelog History
-
v2.0.1 Changes
April 22, 2026secure v2.0.1
0️⃣ secure v2.0.1 introduces a cleaner public API, modern preset defaults, first-class ASGI and WSGI middleware, and safer header handling across supported Python web frameworks.
0️⃣ Compared with v1.0.1, v2 keeps the core
Secure,with_default_headers(),from_preset(),set_headers(), andset_headers_async()APIs, but changes defaults, adds middleware and normalization helpers, and makesSecure.headersstricter and effectively read-only. Notably, neither v1 nor v2 exposessecure. __version__as a public attribute, so version checks should use package metadata rather than module attributes.Highlights
- 🆕 New preset model with
Preset.BALANCEDas the recommended default - First-class
SecureASGIMiddlewareandSecureWSGIMiddleware - 🆕 New header pipeline helpers for allowlisting, deduplication, and normalization
Expanded header coverage, including:
Cross-Origin-Resource-PolicyX-DNS-Prefetch-ControlX-Permitted-Cross-Domain-Policies
Clearer migration path for users coming from v1 manual response mutation patterns
Key improvements
Middleware
v2 adds framework-agnostic middleware in
secure.middleware:SecureASGIMiddleware(app, *, secure=None, multi_ok=None)SecureWSGIMiddleware(app, *, secure=None, multi_ok=None)
This gives ASGI and WSGI applications a cleaner integration path than manually mutating each response.
Header pipeline helpers
v2 adds new helpers on
Secure:allowlist_headers()deduplicate_headers()validate_and_normalize_headers()header_items()
These make it easier to inspect, normalize, and safely emit headers, especially in applications that may need duplicate-aware handling for multi-valued headers.
🆕 New public builders and constants
v2 adds:
CrossOriginResourcePolicyXDnsPrefetchControlXPermittedCrossDomainPoliciesMULTI_OKCOMMA_JOIN_OK- 👍
DEFAULT_ALLOWED_HEADERS
More predictable header state
v2 tracks
headers_listmutations correctly. In v1, once.headershad been read, later mutations toheaders_listcould leave.headersstale because it was backed by a cached property.💥 Breaking changes
Secure.headersis stricterIn v1,
Secure.headerswas a cacheddict[str, str], and duplicate header names silently collapsed to the last value.In v2:
Secure.headersis an immutable mapping- duplicate header names, case-insensitive, raise
ValueError
If your application intentionally or accidentally creates duplicate header names, do not rely on
.headersas the source of truth. Useheader_items()for ordered inspection, or calldeduplicate_headers()before applying headers.0️⃣ Default headers changed
0️⃣
Secure.with_default_headers()no longer means the same thing it meant in v1.- 0️⃣ In v1,
with_default_headers()includedCache-Control: no-store - 0️⃣ In v2,
with_default_headers()maps toPreset.BALANCED, which does not include that same default cache behavior
0️⃣ If you relied on the v1 default cache policy, add it explicitly in v2.
Presets changed materially
v1 included
Preset.BASICandPreset.STRICT.0️⃣ v2 adds
Preset.BALANCED, andSecure.with_default_headers()now maps to that new preset.This also means
Preset.BASICin v2 is not the old BASIC. Compared with v1 BASIC, v2 BASIC adds or changes:- COOP
- CORP
- CSP
- HSTS with
includeSubDomains X-DNS-Prefetch-ControlX-Permitted-Cross-Domain-PoliciesOrigin-Agent-ClusterX-Download-OptionsX-XSS-Protection
0️⃣ and drops v1 BASIC defaults such as:
ServerCache-Control
Preset.STRICTalso changed:- 🔒 v1 STRICT used
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload - 🚚 v2 STRICT removes
preloadby default - v2 STRICT changes cache control from
no-storetono-store, max-age=0
💅 If you need v1-style HSTS preload behavior, configure it explicitly in v2.
FastAPI integration changed in practice
There is no
secure.framework.fastapihelper in either version.- v1 had no framework module at all
- v2 introduces generic ASGI and WSGI middleware instead
⬆️ For FastAPI and other ASGI frameworks, the recommended upgrade path is to move from per-response mutation to
SecureASGIMiddleware.➕ Added
SecureASGIMiddlewareSecureWSGIMiddlewareallowlist_headers(...)deduplicate_headers(...)validate_and_normalize_headers(...)header_items()CrossOriginResourcePolicyXDnsPrefetchControlXPermittedCrossDomainPoliciesMULTI_OKCOMMA_JOIN_OK- 👍
DEFAULT_ALLOWED_HEADERS
🔄 Changed
- 0️⃣
Secure.with_default_headers()now returns the balanced preset - header deduplication and normalization are now first-class operations
- 💅 response integration is more robust across sync and async styles
- applications with duplicate header names now fail fast instead of silently collapsing values
- framework guidance now emphasizes middleware-based integration for ASGI and WSGI apps
Migration guide (v1 → v2)
0️⃣ 1. Review your defaults
- Audit any code that reads
Secure.headers
🚚 3. Move ASGI and WSGI apps to middleware
FastAPI example
💅 Before, v1-style manual response mutation
fromfastapiimportFastAPI,RequestfromsecureimportSecureapp=FastAPI()secure\_headers=Secure.with\_default\_headers()@app.middleware("http")asyncdefadd\_security\_headers(request:Request,call\_next):response=awaitcall\_next(request)awaitsecure\_headers.set\_headers\_async(response)returnresponse💅 After, v2-style ASGI middleware
fromfastapiimportFastAPIfromsecureimportSecurefromsecure.middlewareimportSecureASGIMiddlewareapp=FastAPI()secure\_headers=(Secure.with\_default\_headers() .deduplicate\_headers(action="last") .validate\_and\_normalize\_headers() )app.add\_middleware(SecureASGIMiddleware,secure=secure\_headers)⬆️ Upgrade in 3 steps
0️⃣ 1. Replace any assumption that
with_default_headers()means the same defaults as v1 ⚡️ 2. Audit code that readsSecure.headersand update duplicate-header handling 🚚 3. For ASGI and WSGI apps, move from per-response header mutation to middleware with a pre-normalizedSecureinstanceSummary
🌐 v2.0.1 keeps the core Secure API intact while making the library safer and easier to integrate in modern Python web applications. The biggest changes are the new preset model, middleware-first integration for ASGI and WSGI frameworks, and stricter handling of duplicate and normalized headers.
- 🆕 New preset model with
-
v2.0.0.rc1 Changes
December 16, 2025A release-candidate for secure v2.0.0 focused on a cleaner public API, modern presets, first-class ASGI/WSGI middleware , and safer header application/validation across frameworks.
Highlights
- New preset model with a recommended default:
Preset.BALANCED - New ASGI + WSGI middleware for framework-agnostic integration
- New header pipeline helpers for allowlisting, deduping, and validation/normalization
- 📄 Expanded header coverage and improved docs, examples, and migration guidance
💥 Breaking changes
0️⃣ Presets redesigned and defaults changed
- Added
Preset.BALANCED, now the recommended default. Secure.with_default_headers()now equalsSecure.from_preset(Preset.BALANCED).Preset.BASICtargets Helmet.js default parity.Preset.STRICTno longer enables HSTS preload by default (opt-in separately).
- Added
Secure.headersis now strict about duplicates- Duplicate header names (case-insensitive) raise
ValueError. - Use
header_items()for multi-valued emission, or resolve duplicates viadeduplicate_headers()/validate_and_normalize_headers().
- Duplicate header names (case-insensitive) raise
➕ Added
Middleware
SecureASGIMiddleware(intercepts ASGIhttp.response.start)SecureWSGIMiddleware(wraps WSGIstart_response)secure.middlewarere-exports both; supportsmulti_okfor safely appending multi-valued headers (e.g. CSP)
Header pipeline helpers on
Secureallowlist_headers(...)(raise/drop/warn)deduplicate_headers(...)(raise,first,last,concat) withCOMMA_JOIN_OKandMULTI_OKvalidate_and_normalize_headers(...)(RFC 7230 token validation, CR/LF hardening, optional obs-text, immutable normalized override)
Serialization
header_items()for ordered(name, value)output without enforcing uniqueness
Constants / policies
MULTI_OK,COMMA_JOIN_OK,DEFAULT_ALLOWED_HEADERSOnInvalidPolicy,OnUnexpectedPolicy,DeduplicateAction
Expanded header coverage
Cross-Origin-Resource-PolicyX-DNS-Prefetch-ControlX-Permitted-Cross-Domain-Policies
Project & CI
CODE_OF_CONDUCT.md,CONTRIBUTING.md- GitHub Actions for multi-version tests + Ruff
🔄 Changed
📄 Docs/README overhaul
- Middleware usage +
multi_oksemantics - Clear preset guidance (
BALANCED/BASIC/STRICT) and documented default header set - New “header pipeline and validation” section (allowlist → dedupe → normalize)
- New error handling/logging guidance (
HeaderSetError,AttributeError,RuntimeError, pipelineValueError) - Supported frameworks list expanded (now includes Dash and Shiny)
- Attribution to MDN and the OWASP Secure Headers Project
- Middleware usage +
Presets behavior
- BASIC adds
Origin-Agent-Cluster,X-Download-Options,X-XSS-Protection: 0for Helmet-parity
- BASIC adds
Response integration
- More robust sync/async detection
- Supports
response.headers.set(...)(Werkzeug-style) - Failures while applying headers are wrapped in
HeaderSetError
Packaging/tooling
pyproject.tomlmodernized (metadata cleanup, setuptools floor bump, Ruff configuration)
✅ Testing
- 🔀 Expanded unit and contract tests, including improved coverage for sync/async response integration paths.
⬆️ Upgrade notes
0️⃣ If you were relying on the previous
with_default_headers()behavior, review the new presets and choose:Preset.BALANCED(default, recommended)Preset.BASIC(Helmet-parity compatibility)Preset.STRICT(hardened; no preload by default)
🔧 If your app needs multi-valued headers, prefer
header_items()and/or configure middlewaremulti_ok.
👀 See the migration guide:
docs/migration.md.What's Changed
- 👷 feat: CI for unit tests + explicit Python 3.13 & 3.14 support by @BoboTiG in #39
- ⚡️ secure v2.0.0rc1: presets redesign, ASGI/WSGI middleware, and header updates by @cak in #40
🆕 New Contributors
Full Changelog : v1.0.1...v2.0.0rc1
- New preset model with a recommended default:
-
v1.0.1 Changes
October 18, 2024🚀 This release focuses on improving the performance of the
Secure.set_headersmethod by reducing redundant type checks. The changes optimize the efficiency when setting multiple headers, especially in frameworks that support both synchronous and asynchronous methods.⚡️ Key updates in v1.0.1:
- 🐎 Performance Improvement : Reduced redundant type checks in
Secure.set_headersandSecure.set_headers_async. This optimizes the process by checking the response type once before looping through headers, enhancing performance for applications with multiple headers. #26 - 🆕 New Tests : Added comprehensive tests to validate async and sync behavior for setting headers, ensuring compatibility across different frameworks.
Special Thanks
A big thank you to @davidwtbuxton for raising the issue and helping us improve the project.
⬆️ How to Upgrade
⬆️ To upgrade to v1.0.1, simply run:
pip install --upgrade secure - 🐎 Performance Improvement : Reduced redundant type checks in
-
v1.0.0 Changes
September 27, 2024⚡️ We’re excited to announce the release of
secure.pyv1.0.0! This is a major update that completely redesigns the library with modern Python support and significant improvements in usability, security, and performance.What's New:
Full API Overhaul: The entire library has been redesigned for Python 3.10+ with a more Pythonic API, leveraging type hints and modern language features like union operators (
|) andcached_property.👌 Improved Framework Support: Enhanced integration for popular web frameworks like FastAPI , Flask , Django , Sanic , Starlette , and more, with improved support for asynchronous frameworks.
Middleware Examples: We've added middleware-based integration examples for supported frameworks, making it easier to apply security headers across your application.
✨ Enhanced Security Defaults: Updated default security headers for stronger protection, including refined Content-Security-Policy (CSP) configurations with
nonceandstrict-dynamicdirectives.👍 Better Type Annotations: The entire codebase now includes better type hints and annotations for an improved developer experience.
💥 Breaking Changes:
API Redesign: The library has undergone a full API redesign, and some previous methods have been deprecated or refactored. Be sure to review the documentation before upgrading.
Python 3.10+ Required: This release drops support for older versions of Python. Ensure you are running Python 3.10 or later before upgrading.
➕ Additional Updates:
- Server Header Handling: Improved handling for overriding
Serverheaders in Uvicorn-based frameworks, with examples on how to prevent default Uvicorn headers. - 📚 Expanded Documentation: Updated and more comprehensive documentation with examples for middleware and asynchronous header application.
We look forward to your feedback! 🚀
-
v0.3.0 Changes
April 27, 2021Breaking Changes
🔄 Changelog:
- Full redesign of Secure API
- 👍 Removal of cookie support
- ➕ Add type hints
- ➕ Add support for FastAPI
- 🔄 Change
Feature-PolicytoPermissions-Policy(#10)
-
v0.2.1 Changes
December 24, 2018🍱 Merry Christmas! 🎅
- ➕ Add support for Masonite
- ✂ Remove trailing semicolon from Feature Policy
- 📇 Rename
Feature.Values.AlltoFeature.Values.All_(shadowed built-in name 'all') - Modify hug implementation for SecureHeaders and SecureCookie
- Upper-case SameSite Enum (
SameSite.LAX/SameSite.STRICT) - ➕ Add SecureHeaders and SecureCookie docstrings
-
v0.2.0 Changes
December 16, 2018- ➕ Add policy builder
SecurePolicies(policies.py) - ➕ Add
Expiresheader for legacy browser support - ➕ Add
max-agedirective toCache-controlheader - 📇 Rename
XXSargument toXXP - 👉 Use native Flask set-cookie
- ➕ Add policy builder