DEBUG must be False in production
DEBUG defaults to False in global_settings.py. Every deployment that leaks a
debug page got there because a project setting, an environment variable or a
container default turned it back on.
The reason this outranks everything else in the checklist is what the debug page contains. On an unhandled exception Django renders the traceback, the local variables in every frame, the settings module, and the SQL queries the request ran. Local variables are where credentials actually live — a database password read into a connection call, an API token in a request header, a decrypted session value.
import os
DEBUG = os.environ.get("DJANGO_DEBUG", "") == "true"Read the default from the environment as off, so that a missing variable fails
closed. DEBUG = os.environ.get("DJANGO_DEBUG", True) fails open, and worse,
DEBUG = os.environ.get("DJANGO_DEBUG") is a non-empty string like "False" — which
is truthy.
python manage.py check --deployYou should not have DEBUG set to True in deployment.The deploy check found DEBUG truthy. This is the highest-value finding the check produces, and it is a warning rather than an error only because the check system cannot know you are deploying.
Read in: django/core/checks/security/base.py — id security.W018Two things about DEBUG that are commonly believed and wrong
Section titled “Two things about DEBUG that are commonly believed and wrong”Django does not sanitize everything on the debug page. It scrubs settings whose
names look sensitive and function arguments marked with @sensitive_variables, but
that is a name-matching heuristic. Anything it does not recognise is rendered.
DEBUG = True does not fully disable host validation. When DEBUG is True
and ALLOWED_HOSTS is empty, Django validates the host against
['.localhost', '127.0.0.1', '[::1]'] rather than accepting anything — the fallback
is in get_host(). This surprises people who expect local development to accept any
Host header, and it is why a container reached by its service name can raise
DisallowedHost in development. See ALLOWED_HOSTS.
Turning DEBUG off changes error handling, not just the error page. Django starts
serving your 500.html template, and if that template does not exist or itself
raises, you get a bare response instead. Render both 404.html and 500.html at
least once before deploying.
DEBUG = False also stops Django serving static files through runserver. That is
correct — in production a real server or WhiteNoise should serve them — but it means
turning the setting off locally makes the site look broken in a way that has nothing
to do with the setting.
Related
Section titled “Related”- ALLOWED_HOSTS — the other half of what
DEBUGchanges - SECRET_KEY — one of the things the debug page can disclose