Summary
The stop_impersonating view was made @csrf_exempt in f644e5a to unblock staff returning to their own account after impersonating a user. The impersonation-stop POST was failing CSRF verification. Exempting the view works around the symptom but masks the real cause and should be treated as temporary.
Why this is not just cosmetic
The banner form already renders {% csrf_token %} (templates/base.html:67), so this is not a missing-token problem. A token is being sent and is still being rejected — something environmental is rejecting a valid request, and we don't currently know what. If we don't understand why it fails here, we can't be sure it isn't (or won't start) failing on other POST forms.
Risk assessment
Practical risk on this specific endpoint is low: stop_impersonating only calls restore_original_login and redirects. It is @login_required and @require_POST. The worst a CSRF attacker achieves is forcing a staff member who is currently impersonating to drop back to their own account — a de-escalation, not a privilege gain, with no data mutation.
The concern is not this endpoint today, it's that:
@csrf_exempt masks an unexplained CSRF failure.
- It sets a precedent that becomes dangerous the moment someone adds real logic to the view.
Likely root causes (to investigate)
The Django CSRF rejection log line states the exact reason. Candidates, most to least likely:
- Origin/Referer rejection behind the proxy.
CSRF_TRUSTED_ORIGINS is derived from ALLOWED_HOSTS / the EXTRA_ALLOWED_HOSTS env var (course_management/settings.py:42-46). If dev.courses.datatalks.club isn't in that env var, HTTPS POSTs get "Origin checking failed" — though this would affect all forms, not just this one.
- Stale/cached token. If the banner-bearing page is served from a cache, the rendered token won't match the user's current
csrftoken cookie. This would be page-specific.
- CSRF cookie lost across the django-loginas session rotation, possibly interacting with
CSRF_COOKIE_SECURE / SameSite behind the TLS-terminating proxy (SECURE_PROXY_SSL_HEADER is set at settings.py:318).
Proposed fix
- Pull the actual CSRF failure reason from dev logs (or reproduce locally) to identify which cause above applies.
- Apply the targeted fix:
- Origin issue → add the host to
EXTRA_ALLOWED_HOSTS.
- Caching issue →
@never_cache the banner-bearing view (keeps CSRF protection).
- Cookie issue → fix the cookie flag / proxy config.
- Remove
@csrf_exempt from stop_impersonating (accounts/views.py:62) once the real cause is fixed.
References
- Commit: f644e5a "Exempt stop_impersonating from CSRF"
accounts/views.py:61-66
templates/base.html:66-71
course_management/settings.py:42-46, :318
Summary
The
stop_impersonatingview was made@csrf_exemptin f644e5a to unblock staff returning to their own account after impersonating a user. The impersonation-stop POST was failing CSRF verification. Exempting the view works around the symptom but masks the real cause and should be treated as temporary.Why this is not just cosmetic
The banner form already renders
{% csrf_token %}(templates/base.html:67), so this is not a missing-token problem. A token is being sent and is still being rejected — something environmental is rejecting a valid request, and we don't currently know what. If we don't understand why it fails here, we can't be sure it isn't (or won't start) failing on other POST forms.Risk assessment
Practical risk on this specific endpoint is low:
stop_impersonatingonly callsrestore_original_loginand redirects. It is@login_requiredand@require_POST. The worst a CSRF attacker achieves is forcing a staff member who is currently impersonating to drop back to their own account — a de-escalation, not a privilege gain, with no data mutation.The concern is not this endpoint today, it's that:
@csrf_exemptmasks an unexplained CSRF failure.Likely root causes (to investigate)
The Django CSRF rejection log line states the exact reason. Candidates, most to least likely:
CSRF_TRUSTED_ORIGINSis derived fromALLOWED_HOSTS/ theEXTRA_ALLOWED_HOSTSenv var (course_management/settings.py:42-46). Ifdev.courses.datatalks.clubisn't in that env var, HTTPS POSTs get "Origin checking failed" — though this would affect all forms, not just this one.csrftokencookie. This would be page-specific.CSRF_COOKIE_SECURE/SameSitebehind the TLS-terminating proxy (SECURE_PROXY_SSL_HEADERis set atsettings.py:318).Proposed fix
EXTRA_ALLOWED_HOSTS.@never_cachethe banner-bearing view (keeps CSRF protection).@csrf_exemptfromstop_impersonating(accounts/views.py:62) once the real cause is fixed.References
accounts/views.py:61-66templates/base.html:66-71course_management/settings.py:42-46,:318