티스토리 수익 글 보기

티스토리 수익 글 보기

[5.2.x] Fixed CVE-2026-6907 — Prevented caching of requests when Var… · django/django@2115d4e · GitHub
Skip to content

Commit 2115d4e

Browse files
committed
[5.2.x] Fixed CVE-2026-6907 — Prevented caching of requests when Vary header contains an asterisk.
Thank you Ahmad Sadeddin for the report and Jacob Walls for the review. Backport of c79bdfc from main.
1 parent 47cf968 commit 2115d4e

3 files changed

Lines changed: 39 additions & 0 deletions

File tree

django/middleware/cache.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ def process_response(self, request, response):
104104
if "private" in response.get("Cache-Control", ()):
105105
return response
106106

107+
# Don't cache responses when the Vary header contains '*'.
108+
if has_vary_header(response, "*"):
109+
return response
110+
107111
# Page timeout takes precedence over the "max-age" and the default
108112
# cache timeout.
109113
timeout = self.page_timeout

docs/releases/5.2.14.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,13 @@ a cached public page.
3131

3232
This issue has severity "low" according to the :ref:`Django security policy
3333
<security-disclosure>`.
34+
35+
CVE-2026-6907: Potential exposure of private data due to incorrect handling of ``Vary: *`` in ``UpdateCacheMiddleware``
36+
=======================================================================================================================
37+
38+
Previously, :class:`~django.middleware.cache.UpdateCacheMiddleware` would
39+
erroneously cache requests where the ``Vary`` header contained an asterisk
40+
(``'*'``). This could lead to private data being stored and served.
41+
42+
This issue has severity "low" according to the :ref:`Django security policy
43+
<security-disclosure>`.

tests/cache/tests.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2505,6 +2505,18 @@ def hello_world_view(request, value):
25052505
return HttpResponse("Hello World %s" % value)
25062506

25072507

2508+
def hello_world_view_patch_vary_headers_asterisk(request, value):
2509+
response = HttpResponse("Hello World %s" % value)
2510+
patch_vary_headers(response, ("*",))
2511+
return response
2512+
2513+
2514+
def hello_world_view_vary_headers_includes_asterisk(request, value):
2515+
response = HttpResponse("Hello World %s" % value)
2516+
response["Vary"] = "Cookie, *, Pony"
2517+
return response
2518+
2519+
25082520
def csrf_view(request):
25092521
return HttpResponse(csrf(request)["csrf_token"])
25102522

@@ -2733,6 +2745,19 @@ def test_cached_control_private_not_cached(self):
27332745
response = view_with_private_cache(request, "2")
27342746
self.assertEqual(response.content, b"Hello World 2")
27352747

2748+
def test_vary_asterisk_not_cached(self):
2749+
views_with_cache = (
2750+
cache_page(3)(hello_world_view_patch_vary_headers_asterisk),
2751+
cache_page(3)(hello_world_view_vary_headers_includes_asterisk),
2752+
)
2753+
for view in views_with_cache:
2754+
with self.subTest(view=view):
2755+
request = self.factory.get("/view/")
2756+
response = view(request, "1")
2757+
self.assertEqual(response.content, b"Hello World 1")
2758+
response = view(request, "2")
2759+
self.assertEqual(response.content, b"Hello World 2")
2760+
27362761
def test_sensitive_cookie_not_cached(self):
27372762
"""
27382763
Django must prevent caching of responses that set a user-specific (and

0 commit comments

Comments
 (0)