LOW 3.1

CVE-2026-48587: Django Cache Header Bypass – Whitespace Handling Vulnerability

Django's cache handling function has a flaw where whitespace in HTTP Vary headers isn't properly cleaned up before comparison. An attacker can exploit this by crafting requests that cause the application to serve cached responses intended for different users, potentially leaking sensitive information. The vulnerability affects Django 5.2 before version 5.2.15 and 6.0 before version 6.0.6, though older unsupported versions may also be vulnerable.

Source data · NVD / CISA · public domain

CVSS
3.1 · 3.1 LOW · CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N
Weaknesses (CWE)
CWE-1023
Affected products
1 configuration(s)
Published / Modified
2026-06-03 / 2026-06-17

NVD description (verbatim)

An issue was discovered in Django 5.2 before 5.2.15 and 6.0 before 6.0.6. `django.utils.cache.has_vary_header()` in Django does not strip leading or trailing whitespace from `Vary` response header values before comparison, which allows remote attackers to read cached responses via requests to URLs whose responses contain whitespace-padded Vary header values. Earlier, unsupported Django series (such as 5.0.x, 4.1.x, and 3.2.x) were not evaluated and may also be affected. Django would like to thank Navid Rezazadeh for reporting this issue.

3 reference(s) · View on NVD →

SEC.co analysis · AI-assisted, reviewed against source

Technical summary

The `django.utils.cache.has_vary_header()` function in Django fails to strip leading and trailing whitespace from Vary response header values during comparison operations. The Vary header is critical for cache key differentiation—it tells caching systems which request headers affect the response. By submitting requests with whitespace-padded Vary values, an attacker can bypass cache validation logic and retrieve responses cached for different request variants. This occurs because string comparison in the vulnerable code does not normalize whitespace, allowing semantically identical headers (e.g., 'Accept' vs ' Accept ') to be treated as distinct. The issue is classified under CWE-1023 (Comparison Using Wrong Factors), as the function uses incomplete input normalization before cache-critical decisions.

Business impact

Cache poisoning via this vulnerability can lead to unauthorized information disclosure. A user could receive cached responses generated for other users, potentially exposing personally identifiable information, session tokens, or other sensitive data. The impact is limited to confidentiality; there is no integrity or availability risk. Organizations relying on Django caching for performance-critical or multi-tenant applications face the greatest risk. Public-facing web applications and APIs serving different response variants based on request headers are most vulnerable. Data breaches from such cache leaks could trigger regulatory scrutiny and reputation damage.

Affected systems

Django 5.2 versions prior to 5.2.15 and Django 6.0 versions prior to 6.0.6 are confirmed affected. The Django project notes that unsupported legacy series—including 5.0.x, 4.1.x, and 3.2.x—have not been formally evaluated but may also be vulnerable due to shared code ancestry. Organizations using any of these versions should treat this as a potential risk. Versions 5.2.15, 6.0.6, and later contain the fix.

Exploitability

Exploitation requires network access to a vulnerable Django application and user interaction (reflected in the CVSS vector's UI:R component). An attacker must craft a malicious request containing whitespace-padded Vary header values and trick a user into following a link or making a request that triggers cache lookup. The attack is not trivial—it requires understanding of the target application's cache configuration and which header variations produce different responses. There is no public exploit code, and the vulnerability has not been added to the CISA Known Exploited Vulnerabilities catalog. Practical attacks are therefore limited to sophisticated threat actors with application-specific knowledge.

Remediation

Upgrade Django 5.2 installations to version 5.2.15 or later, and Django 6.0 installations to version 6.0.6 or later. The patch implements proper whitespace stripping in the `has_vary_header()` function before header comparison. For unsupported Django versions (3.2.x, 4.1.x, 5.0.x), no official patches are available; users must upgrade to a supported release or implement custom middleware to normalize Vary headers. As an interim compensating control, disable or reduce cache ttl for responses with user-specific or sensitive content.

Patch guidance

Django 5.2 users should prioritize updating to 5.2.15 or the latest 5.2.x release. Django 6.0 users should update to 6.0.6 or later. Both patches are maintenance/security releases and should be low-risk for production deployment, though regression testing of cache behavior is recommended. Verify the applied version post-deployment by checking `django.VERSION` or `pip show django`. Coordinate patching across development, staging, and production environments to ensure consistent cache behavior. For organizations on unsupported versions, evaluate the cost of upgrading to Django 5.2 LTS or 6.0 against the risk of remaining vulnerable.

Detection guidance

Monitor application logs for unusual cache hit patterns, particularly responses served to different users with identical content. Inspect Vary header values in HTTP responses using browser developer tools or network analysis tools (tcpdump, Wireshark) to identify whitespace padding. Review Django cache middleware configuration and access logs for requests with non-standard header formatting. Web Application Firewalls (WAF) with header normalization rules can help, though they may not catch all variants. Implement custom Django middleware to log cache hits with associated request headers, enabling anomaly detection of users receiving unexpected cached content.

Why prioritize this

Although the CVSS score of 3.1 is low, the vulnerability directly threatens confidentiality of cached user data in multi-tenant or personalized environments. Organizations with Django applications serving sensitive information via caching should prioritize patching. The requirement for user interaction and high attack complexity reduce risk for most deployments, but the potential for silent data leakage justifies moderate prioritization. Unsupported version users face higher risk and should elevate this in their remediation queue.

Risk score, explained

The CVSS 3.1 score of 3.1 (Low) reflects low attack vector complexity, requirement for user interaction, and limited scope. However, this numeric score understates reputational and compliance risk in data-handling scenarios. The vulnerability is not a remote code execution or denial-of-service vector, and exploitation requires application-specific conditions. The score appropriately downgrades severity due to the UI requirement and the need for the attacker to have prior knowledge of cache configuration.

Frequently asked questions

Can this vulnerability be exploited if we use a Content Delivery Network (CDN) instead of Django's built-in cache?

Partially. If your CDN performs its own cache validation, it may bypass this Django-level bug. However, if the CDN forwards the malformed Vary header to Django or relies on Django's cache headers, the vulnerability can still be triggered. Test your CDN configuration to confirm whether whitespace-padded Vary headers pass through to your origin server. CDN-level caching does not eliminate the need to patch Django.

Does this affect only HTTP caching, or does it also impact session storage and database query caching?

This vulnerability is specific to HTTP response caching managed by `django.utils.cache.has_vary_header()`. It does not directly affect Django's session framework, database caching backends (Redis, Memcached), or ORM query caching, which use different comparison mechanisms. However, if your application uses the vulnerable caching function to control query cache keys based on Vary headers, secondary impact is possible. Audit your custom caching logic for similar whitespace handling issues.

What is the difference between this issue and cache poisoning attacks?

Traditional cache poisoning injects malicious content into the cache. This vulnerability is a cache bypass or cache misdelivery issue—an attacker doesn't poison the cache; they retrieve legitimate cached content intended for a different user by manipulating header formatting. The distinction matters: cache poisoning is often site-wide, while this vulnerability targets specific user sessions, making it harder to detect but more targeted in impact.

Do we need to clear the cache after patching?

It is not strictly necessary, as the cached content itself is not corrupted. However, clearing the cache after deploying the patch is a prudent practice to ensure that any responses cached by the vulnerable code are flushed. This prevents edge cases where stale cache keys containing whitespace anomalies persist. Use Django's `cache.clear()` during your maintenance window or in your post-deployment verification script.

This analysis is provided for informational purposes to help organizations assess and remediate CVE-2026-48587. It is not a substitute for vendor advisories or independent security assessment. Patch version numbers and affected product details are sourced from official Django project security releases; verify against the latest Django security bulletins before deployment. No exploit code, weaponized proof-of-concept, or intrusion detection signatures are provided. Organizations should conduct their own risk assessment based on their Django deployment topology, cache configuration, and data sensitivity. SEC.co makes no warranty regarding the completeness or timeliness of this information. Source: NVD (public-domain), retrieved 2026-07-07. Analysis generated by SEC.co (claude-haiku-4-5).