Skip to content

Django

Facts last verified 2026-07-26 against Django 6.0.7

Django ships with more security switched on than most frameworks, and that changes what this cluster is for. The work is rarely adding protections. It is finding the ones a previous deploy turned off, and the ones a version upgrade quietly redefined.

Several behaviours here changed on a version boundary, so the version is the first input, not a footnote:

Terminal window
python -c "import django; print(django.get_version())"
  • Django 6.0.7 is current, and 6.0 is the first release with built-in CSP.
  • 5.2 is the LTS, supported to April 2028 — and it does not have built-in CSP.
  • 5.1 (end of life December 2025) and 5.0 are both past support.

If that prints something older than 4.0, several pages here describe a different framework than the one you are running — SECURE_BROWSER_XSS_FILTER still exists for you, and CSRF_TRUSTED_ORIGINS still takes bare hostnames.

Django can audit its own deployment settings, and it is consistently the most under-used command in the framework:

Terminal window
python manage.py check --deploy

Every finding it emits carries a stable id — security.W018, security.W020, 4_0.E001 — and each id maps to exactly one page below. Put it in CI rather than relying on someone remembering to run it.

Two things it will not tell you:

  • ALLOWED_HOSTS = ["*"] passes. The check tests only that the list is non-empty.
  • A setting that no longer exists passes. Unknown names in a settings module are ignored, so a removed setting sits there looking like a control.

Severity is the exposure a control closes, not how hard it is or how often it gets recommended. Two entries here are rated low and say so on the page.

DEBUG must be False in productionSettings, SQL queries and local variables served to anyone who triggers an errorSeverity: critical
SECRET_KEY strength and rotationForged sessions, password-reset tokens and signed cookiesSeverity: critical
ALLOWED_HOSTS and the leading-dot trapHost header attacks — poisoned reset links, poisoned cachesSeverity: high
CSRF_TRUSTED_ORIGINS must carry a schemeCross-origin POSTs rejected, or trusted from origins you did not intendSeverity: high
Session and CSRF cookie flagsSession and CSRF cookies sent over plaintext, or readable by injected scriptSeverity: high
SSL redirect behind a proxyRedirect loops, or a spoofable header that makes every request look secureSeverity: medium
Security headers and SecurityMiddlewareMissing HSTS, or headers silently absent because the middleware is not installedSeverity: medium
Content Security Policy — three different answersInjected script executing with no policy to stop itSeverity: medium
Clickjacking protectionThe site framed by an attacker's page to hijack clicksSeverity: low
SECURE_BROWSER_XSS_FILTER was removedNone — this page exists to stop you re-adding a header that can create vulnerabilitiesSeverity: low
Host header poisoningA forged Host header becomes an absolute URL in an email you sentSeverity: high
0 of 11 applied

TLS termination, the web server in front of Django, and the container it runs in. That is the server’s half rather than the application’s — see application vs server for the dividing line, and for the three controls that genuinely span both.