Security overview#
next.dj relies on Django’s middleware stack and template engine for the bulk of its security guarantees. This page lists the Django mechanisms that apply unchanged and the framework specific surfaces that need extra attention.
Django guarantees used unchanged#
The framework does not bypass any standard Django middleware.
CSRF tokens flow through the standard CsrfViewMiddleware.
Session management uses the standard SessionMiddleware.
Authentication uses
AuthenticationMiddlewareand the standard auth backends.Permissions checking, password hashing, and signed cookies remain unchanged.
Django template engine auto escaping is active for every page and component template.
A standard MIDDLEWARE block in settings.py is therefore enough to inherit the full Django security baseline.
Framework specific surfaces#
The framework adds four surfaces that warrant attention.
- File router input.
Captured URL parameters and query values reach Python through the dependency resolver. Treat them as untrusted, see DI and untrusted input.
- Form dispatch path.
/_next/form/<uid>/is the dispatch endpoint for every action. See CSRF and forms for the CSRF flow.- Co-located assets.
Component and page level CSS and JS ship through the static collector. See Static asset security for origins, hashes, and integrity.
- Partial rendering endpoints.
Zone GET requests and the SSE stream answer partial clients. See Partial rendering for the surface and Access control for the foreign-page rules.
Common threats#
- CSRF.
Django middleware plus the framework
{% form %}tag covers the standard form path. Manual<form>elements need explicit{% csrf_token %}.- XSS.
Django template auto escaping prevents most cases. Context functions that return
mark_safestrings or HTML strings bypass escaping. Applymark_safeonly to values you fully control, and never to untrusted input as covered in DI and untrusted input. The framework escapes<,>,&, U+2028, and U+2029 in the inline init payload, so a serialised value that contains</script>cannot break out of the tag. The remaining risk is that serialised values appear in the page source, so never mark a secretserialize=True, see Static asset security.- SQL injection.
The Django ORM uses parameterised queries. Raw SQL inside a custom provider must use
params. See DI and untrusted input for the custom-provider validation pattern.- Mass assignment.
Whitelist editable fields on
ModelForm, see DI and untrusted input for the rule.- Origin spoofing.
The only page identity a form submission carries is the
_next_form_originURL path, which the dispatcher resolves through the URLconf withdjango.urls.resolve(). The client never supplies a filesystem path, so an error re-render can target only pages that are reachable through the routing table anyway. A value that does not resolve returns HTTP 400. Substituting the origin of another routed page remains possible and is an authorization question, so guard mutating actions as described under Access control.- Open redirect.
HttpResponseRedirectaccepts any URL. Validate destinations before passing user input into a redirect target. The partialredirect(href, external=True)patch is the same escape hatch on the client side, see Server-authored redirects.- Object-level authorization.
A lookup keyed only on a URL value loads whatever row matches, regardless of who owns it. The ModelForm
Meta.instance_from_urllookup is unscoped, so scope it to the user or tenant. See ModelForms for the ownership-scoped pattern and DI and untrusted input for the posted origin path that feeds the lookup.
Access control#
Form actions are unauthenticated by default.
The /_next/form/<uid>/ endpoint accepts a POST from any visitor, so a registered edit or delete action runs without an identity check unless the handler adds one.
Enforce access at one of these layers.
Declare
Meta.login_requiredandMeta.permission_requiredon the form class, or the same keywords on@action, for a static guard checked before any application code, see Access guards.Override
check_permissionsorhas_object_permissionon the form class for a per-request decision against the database, the tenant, or the loaded row, see Dynamic permission hooks.Check
request.user.is_authenticatedand ownership insideon_validbeforeself.save().Apply a project-wide login requirement through middleware, see Require login on file-routed pages.
Enforce a policy in a custom form action backend that wraps every dispatch.
An action that mutates data and an action that loads an instance through instance_from_url both need this guard.
The Enforce object-level permissions recipe shows the owner-only edit on a ModelForm.
The out-of-band morph path enforces page-level access on its own.
A morph(zone=..., page=...) onto a foreign page re-runs that page’s authorization chain and raises ForeignPageNotAuthorizedError on a denial or DynamicForeignPageError for a dynamic body, see Partial rendering reference.
Production hardening#
A short list of production specific settings.
Set
SECURE_SSL_REDIRECT = Trueto redirect every HTTP request to HTTPS.Set
SECURE_CONTENT_TYPE_NOSNIFF = Trueto block MIME-type sniffing.Set
SECURE_HSTS_SECONDS = 31536000to send a one-year HSTS header.Set
SECURE_HSTS_INCLUDE_SUBDOMAINS = Trueto extend HSTS to all subdomains.Set
SECURE_HSTS_PRELOAD = Trueto allow submission to the HSTS preload list.Set
SESSION_COOKIE_SECURE = Trueto send the session cookie only over HTTPS.Set
CSRF_COOKIE_SECURE = Trueto send the CSRF cookie only over HTTPS.Set
CSRF_TRUSTED_ORIGINS = ["https://..."]to restrict cross-origin form submissions to listed origins.
Run uv run python manage.py check --deploy and resolve every warning.
See Deployment checklist for the full pre-deploy review.
System checks#
The framework system checks cover configuration mistakes that affect security.
next.E041reports two actions registered under the same name from different handlers.next.E045reports a form action backend that does not subclassFormActionBackend.next.E020reports a component registered more than once within the same scope.
Run them with uv run python manage.py check.
See also#
See also
CSRF and forms for the form pipeline. Static asset security for the static pipeline. DI and untrusted input for the dependency surface. JavaScript context for runtime script options that interact with CSP. Reporting a vulnerability for vulnerability disclosure.