Vulnerability
Django

CSRF in Django Applications

Django includes robust built-in CSRF protection via CsrfViewMiddleware and the {% csrf_token %} template tag. However, developers weaken this protection by using @csrf_exempt decorators, misconfiguring AJAX requests, and bypassing middleware for API views.

Scan Your Django App

How CSRF Manifests in Django

Django's CSRF protection fails when developers: - Use @csrf_exempt on views to fix "403 CSRF token missing" errors without understanding the security implications - Exclude entire URL patterns from CSRF middleware in settings - Forget to include {% csrf_token %} in forms - Misconfigure AJAX requests to not send the CSRF cookie Django REST Framework views use their own authentication and may bypass Django's CSRF middleware. SessionAuthentication in DRF includes CSRF checking, but TokenAuthentication does not, leading to confusion about which views need CSRF protection.

Real-World Impact

A Django application for managing employee records used @csrf_exempt on the API endpoints because the developer could not get AJAX CSRF tokens working. An attacker sent a phishing email to HR staff linking to a page that submitted hidden requests to change employee bank account details for payroll deposits.

Step-by-Step Fix

1

Include CSRF token in all forms

Always use {% csrf_token %} in Django template forms.

<!-- Always include csrf_token in POST forms -->
<form method="post" action="/update-profile/">
  {% csrf_token %}
  <input type="text" name="name" value="{{ user.name }}">
  <button type="submit">Update</button>
</form>
2

Configure AJAX CSRF headers

Send the CSRF token with all AJAX requests using the X-CSRFToken header.

// Get CSRF token from cookie
function getCookie(name) {
  let cookieValue = null;
  if (document.cookie) {
    const cookies = document.cookie.split(';');
    for (let cookie of cookies) {
      cookie = cookie.trim();
      if (cookie.startsWith(name + '=')) {
        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
        break;
      }
    }
  }
  return cookieValue;
}

// Use with fetch
fetch('/api/update/', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRFToken': getCookie('csrftoken'),
  },
  body: JSON.stringify(data),
});
3

Remove @csrf_exempt decorators

Replace @csrf_exempt with proper CSRF token handling.

# UNSAFE - disables CSRF protection
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def update_profile(request):
    # No CSRF protection!
    pass

# SAFE - require CSRF token
def update_profile(request):
    # CSRF middleware validates the token automatically
    pass

# For webhook endpoints that need @csrf_exempt,
# implement alternative auth:
@csrf_exempt
def stripe_webhook(request):
    sig = request.META.get('HTTP_STRIPE_SIGNATURE')
    try:
        event = stripe.Webhook.construct_event(
            request.body, sig, WEBHOOK_SECRET
        )
    except (ValueError, stripe.error.SignatureVerificationError):
        return HttpResponse(status=400)
    # Process event...

Prevention Best Practices

1. Never use @csrf_exempt unless absolutely necessary (e.g., webhook endpoints with their own auth). 2. Always include {% csrf_token %} in HTML forms. 3. Configure AJAX requests to send the csrftoken cookie value in the X-CSRFToken header. 4. Use CSRF_TRUSTED_ORIGINS for cross-origin requests instead of disabling CSRF. 5. In DRF, use SessionAuthentication which includes CSRF checking.

How to Test

1. Search for @csrf_exempt in your codebase: grep -rn "csrf_exempt" --include="*.py" 2. Check that all HTML forms include {% csrf_token %}. 3. Verify AJAX requests send X-CSRFToken header. 4. Test by submitting a cross-origin form to your mutation endpoints. 5. Use Vibe App Scanner to detect CSRF weaknesses in your Django application.

Frequently Asked Questions

Does Django have built-in CSRF protection?

Yes. Django includes CsrfViewMiddleware by default and the {% csrf_token %} template tag. This provides robust CSRF protection for HTML form submissions. However, developers often weaken it with @csrf_exempt or by not configuring AJAX requests correctly.

Why do I get 403 Forbidden CSRF errors in Django?

The 403 error means the CSRF token is missing or invalid. For forms, add {% csrf_token %}. For AJAX, send the csrftoken cookie value in the X-CSRFToken header. Do not use @csrf_exempt to "fix" this error - it disables security.

Does Django REST Framework need CSRF protection?

It depends on the authentication method. SessionAuthentication includes CSRF checking automatically. TokenAuthentication and JWT do not need CSRF protection because they use Authorization headers. If you support both session and token auth, CSRF is checked only for session-authenticated requests.

Is Your Django App Vulnerable to CSRF?

VAS automatically scans for csrf vulnerabilities in Django applications and provides step-by-step remediation guidance with code examples.

Scans from $5, results in minutes. Get actionable fixes tailored to your Django stack.