django-csp
Content-Security-Policy header management for Django, with per-view overrides and nonce support.
Repository Health
Technical Analysis
django-csp is a lightweight Django middleware library, maintained by Mozilla, that generates and attaches Content-Security-Policy (CSP) and CSP-Report-Only response headers based on settings defined in CONTENT_SECURITY_POLICY and CONTENT_SECURITY_POLICY_REPORT_ONLY. It has been protecting Django sites against XSS and data-injection attacks since 2010, and version 4.0 introduced a settings-driven configuration format alongside CSP keyword constants like SELF, NONE, and STRICT_DYNAMIC.
Beyond a global policy, django-csp exposes per-view decorators (@csp, @csp_update, @csp_replace, @csp_exempt) for adjusting or exempting a policy on individual views, a lazily-generated per-request nonce accessible as request.csp_nonce for allow-listing inline scripts without unsafe-inline, and a RateLimitedCSPMiddleware for throttling how often violation reports get sent to a report-uri. Template tags and a Jinja2 extension make it straightforward to emit correctly nonced <script> tags from templates.
What You Get
- Global CSP/CSP-Report-Only header generation driven entirely by Django settings
- Per-view decorators (@csp, @csp_update, @csp_replace, @csp_exempt) for adjusting or exempting policy on individual views
- A request.csp_nonce lazy nonce plus a context processor and template tag/Jinja2 extension for correctly nonced inline scripts
- RateLimitedCSPMiddleware to throttle the percentage of requests that send violation reports to report-uri
Common Use Cases
- Locking down a Django app’s script/style/frame sources to mitigate XSS
- Rolling out a stricter policy safely via CONTENT_SECURITY_POLICY_REPORT_ONLY before enforcing it
- Allow-listing specific inline scripts with per-request nonces instead of unsafe-inline
- Exempting or loosening the policy for specific views such as third-party embeds or admin tools
Under The Hood
Architecture
django-csp is organized as a small, flat Django app (the csp package) rather than a layered system: csp/middleware.py holds the single CSPMiddleware (a MiddlewareMixin subclass) that attaches a lazily-generated nonce to the request in process_request and, in process_response, calls into csp/utils.py’s pure build_policy() function twice (once for the enforced policy, once for report-only) to render header strings sourced from PolicyParts — a small dataclass assembled from Django settings and any per-response _csp_config/_csp_update/_csp_replace attributes set by the decorators in csp/decorators.py. This is the core abstraction: policy state travels on the HttpResponse object itself as private attributes rather than through a request context, so decorators can mutate policy per-view without global state, and RateLimitedCSPMiddleware in csp/contrib/rate_limiting.py composes on top by subclassing CSPMiddleware and overriding get_policy_parts() to strip report-uri/report-to for a random subset of requests. Template rendering (csp/templatetags/csp.py’s script tag and csp/extensions/__init__.py’s Jinja2 NoncedScript extension) both funnel through the same build_script_tag() helper in utils.py. If build_policy()’s directive-merging precedence changed, every downstream feature — decorators, middleware, rate limiting — would need re-verification since they all depend on its exact config/update/replace semantics.
Tech Stack
The only runtime dependencies are django>=4.2 and packaging (used in csp/checks.py to gate a Django system check by installed version), with an optional extra for jinja2>=2.9.6 powering the Jinja2 template extension. The package targets Python 3.9-3.13 plus PyPy, and Django 4.2 through 5.2, uses a pyproject.toml-only setuptools build, and ships fully type-annotated code (a py.typed marker is present) checked with mypy --strict via the django-stubs plugin. Tooling is Ruff for linting and formatting, tox/tox-gh-actions to run the test matrix across Python/Django/PyPy combinations, and pre-commit hooks enforced before merge. Documentation is built with Sphinx and hosted on Read the Docs, and releases publish to PyPI via a GitHub Actions job gated on a published GitHub release.
Code Quality
Testing uses pytest with pytest-django and pytest-cov, plus pytest-ruff wired into pyproject.toml’s addopts so lint/format checks run as part of the test suite itself; the csp/tests/ directory has one test module per source file, using Django’s RequestFactory and override_settings extensively to cover header-generation edge cases like set-typed directive values and simultaneous enforced/report-only policies. Error handling is explicit and typed — a dedicated CSPNonceError exception guards against reading request.csp_nonce after the response has already been written — and csp/checks.py registers real Django system checks that surface actionable warnings, including an auto-generated migration snippet, when a project is still using the pre-4.0 CSP_* settings format. Every module uses from __future__ import annotations plus full type hints, naming is consistent snake_case throughout, and CI runs the full matrix of Python/PyPy versions on every push and PR.
API Design
django-csp’s main technical distinctions are its per-response, decorator-driven policy model — storing pending policy changes as private attributes on the HttpResponse object so per-view decorators compose cleanly with global middleware settings — and its treatment of the CSP nonce as a CheckableLazyObject, a SimpleLazyObject subclass whose __bool__ reports whether the nonce was actually generated, letting the middleware detect after the fact whether request.csp_nonce was ever read and skip adding an unused nonce to the header, while raising CSPNonceError if it’s accessed too late to be included. RateLimitedCSPMiddleware’s statistical sampling of violation reports is a small but genuinely useful primitive for running CSP in report-only mode at scale, where full reporting on a busy site can flood a report-uri endpoint. None of this is groundbreaking research — it follows patterns established by similar CSP middlewares in other frameworks — but the settings-migration system checks that auto-generate a new-format config from old CSP_* settings are an unusually developer-friendly touch for a library undergoing a breaking config-format change.
Used by 3 apps in this directory
Docs
File Storage · CMS
Open-source collaborative knowledge platform with real-time editing, AI writing tools, and full self-hosting control — built by the French and German governments.
Label Studio
AI Development · Data Engineering
Label Studio is an open-source, multi-type data labeling platform that lets teams annotate images, text, audio, video, and time series data with a configurable XML-based UI and export annotations in formats ready for any ML framework.
Sentry
Security · Developer Tools · Monitoring
Developer-first error tracking and performance monitoring platform with AI-powered root-cause analysis across 20+ languages and frameworks.