Threat model: says every cookie is HttpOnly, but the CSRF cookie is not #538
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#538
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found on 2026-09-29 in a read-only review of postulo at
95348908d, readingdocs/THREAT-MODEL.mdagainst the cookie settings.Checked again on 2026-10-01 against
mainat0a5cad587: still present.csrfToken()is now called atstatic/js/app.js:2094and:2317(two callers, not one as first written; both pass on the value read from the form field); the settings, the threat model and the test have not moved.The threat model lists "cookies are
SecureandHttpOnly" among the defences against a malicious page the person is on. Only the session cookie isHttpOnly.CSRF_COOKIE_HTTPONLYis never set, so thecsrftokencookie keeps Django's default and is readable by script. The practical exposure is nil, because the same token sits in every form's hiddencsrfmiddlewaretokenfield anyway, but the document states a property the instance does not have, and nothing in the application needs the cookie to be readable.docs/THREAT-MODEL.md:16(the row A malicious page the person is on);config/settings/base.py:692-694, which setSESSION_COOKIE_HTTPONLY = Trueand the twoSameSitevalues only;static/js/app.js:44-47(csrfToken()reads the form field, neverdocument.cookie) andstatic/js/app.js:2094and:2317, its two callers. The allauth trust cookie and Django's message cookie followSESSION_COOKIE_HTTPONLY, so they are covered.csrftokencarriesSecureandSameSite=Laxbut notHttpOnly, contrary to the threat model. Nothing insrc/postulo/staticoutside the vendored files, nor either browser extension, reads the cookie.CSRF_COOKIE_HTTPONLY = Trueinconfig/settings/base.pybesideSESSION_COOKIE_HTTPONLY(safe, sinceapp.jstakes the token from the form), or reword the threat model to "the session cookie isHttpOnly; every cookie isSecure". The first keeps the sentence true as written.Done when
tests/security/test_requests.pyassertsCSRF_COOKIE_HTTPONLYalongside the existingSESSION_COOKIE_SECURE and CSRF_COOKIE_SECUREcheck at line 189 (fails today), or the threat model no longer claims it.Fixed in
ffb060788on main.