#37467 new Bug

delete_cookie() can't delete a cookie named with the __Host-Http- or __Http- prefix

Reported by: albertoflp Owned by:
Component: HTTP handling Version: dev
Severity: Normal Keywords: cookies prefix HttpOnly sessions
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Browsers now enforce two more cookie name prefixes, __Http- and __Host-Http-, from the IETF cookies draft (​draft-ietf-httpbis-layered-cookies, section "The __Host-Http- prefix"): such a cookie must have the Secure and HttpOnly attributes, and a __Host-Http- one also Path=/ and no Domain. In the draft's "Store a Cookie" algorithm, a cookie that fails these requirements is dropped (step 16) before the step that replaces an existing cookie (step 19), and an expired cookie sent to delete one is no exception. Chrome and Edge 140 and Firefox 143 enforce this (​MDN).

HttpResponse.delete_cookie() adds Secure for __Secure- and __Host- names (#28989), but it never sends HttpOnly. A browser that enforces these prefixes therefore ignores the deletion and keeps the cookie.

This matters for the session cookie. RFC 10017 (BCP 212, "OAuth 2.0 for Browser-Based Applications"), section 6.1.3.2, recommends the __Host-Http- prefix for the session cookie of a backend that runs the login. With SESSION_COOKIE_NAME = "__Host-Http-sessionid", SessionMiddleware deletes an emptied session's cookie (after logout(), for example) through delete_cookie(), and Firefox logs:

Cookie "__Host-Http-sessionid" has been rejected for invalid prefix.

The session row is deleted, so the leftover cookie opens nothing. But it stays in the browser until a new session replaces it, and meanwhile the middleware sends the same rejected deletion on every response that reads the session.

Steps to reproduce (Django 5.2.18, and the same code on main):

# settings.py
SESSION_COOKIE_NAME = "__Host-Http-sessionid"
SESSION_COOKIE_SECURE = True
# SESSION_COOKIE_HTTPONLY = True (the default)

Over HTTPS in Firefox 143 or Chrome 140, log in and log out. The logout response carries:

Set-Cookie: __Host-Http-sessionid=""; expires=Thu, 01 Jan 1970 00:00:00 GMT; Max-Age=0; Path=/; SameSite=Lax; Secure

There is no HttpOnly; the console reports the rejection and the cookie remains in storage.

A possible fix, by analogy with #28989: delete_cookie() also sets httponly=True when the name starts with __Http- or __Host-Http-. An alternative is an httponly argument that SessionMiddleware fills from SESSION_COOKIE_HTTPONLY, as #31790 did for samesite, but the prefix rule covers every caller.

Change History (0)

Note: See TracTickets for help on using tickets.
Back to Top