DataTalksClub / DataTalksClub/course-management-platform

stop_impersonating is CSRF-exempt — find root cause and restore protection

Open
#176 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

infra
Dominant language
Python
Stars
85
Forks
37
PR merge metrics
No merged PRs in 30d

Description

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:

  1. 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.
  2. 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.
  3. 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

  1. Pull the actual CSRF failure reason from dev logs (or reproduce locally) to identify which cause above applies.
  2. 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.
  3. 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

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the CSRF failure reason in development logs and the impersonation flow in accounts/views.py:61-66. Check the banner form in templates/base.html:66-71 and the host, proxy, and cookie settings in course_management/settings.py:42-46 and :318, then reproduce the POST if needed. Done means the root cause is fixed, CSRF protection remains enabled, and @csrf_exempt is removed from stop_impersonating.

Written by the indexing model from the issue text.

Assessment

Tech stack
django, python
Domain
authentication, backend, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.