HTTP routes that do not explicitly restrict which HTTP methods are allowed accept both safe (read-only) and unsafe (state-changing) methods, which can expose the application to CSRF attacks.
HTTP methods are divided into safe methods (GET, HEAD, OPTIONS), which are intended for read-only operations, and unsafe methods (POST, PUT, DELETE), which are intended for state-changing operations. When a route does not restrict which methods it accepts, an attacker can trigger state-changing behavior through a safe method such as GET. CSRF protections typically only apply to unsafe methods, so a route that accepts both can be exploited via a crafted link or image tag without requiring the attacker to bypass CSRF defenses.
An attacker can craft a malicious link or page that causes a victim’s browser to issue a state-changing HTTP request to the vulnerable route. Because the request originates from the victim’s authenticated session, the server processes it as legitimate, allowing the attacker to perform actions such as deleting records, changing account settings, or initiating transactions on behalf of the victim.
The following noncompliant example shows a route that applies no method restriction, allowing any HTTP verb to trigger state-changing behavior. Each compliant example restricts the route to only the methods appropriate for its purpose.
# No method restriction
def view(request): # Noncompliant
return HttpResponse("...")
@require_http_methods(["POST"])
def view(request):
return HttpResponse("...")