Aug 25, 2026·7 min read·25 visits
django CMS versions before 5.0.8 and 5.1.0 contain a cache key computation flaw that ignores plugin-declared HTTP Vary headers, leading to server-side cache poisoning and information disclosure.
Prior to version 5.0.8, django CMS fails to respect dynamically declared Vary HTTP headers in its internal page cache. This allows remote attackers to bypass authorization, leak sensitive information across user sessions, or poison the page cache by sending requests with custom headers.
The core design of django CMS relies on an internal server-side page caching engine, controlled by the CMS_PAGE_CACHE setting, to store fully rendered HTML pages within high-performance key-value backends such as Redis or Memcached. This system acts as a high-speed delivery mechanism, minimizing application layer rendering times and database query operations by serving static variants of content pages directly to inbound web clients.
However, a design discrepancy exists within the caching architecture prior to version 5.0.8. While individual plugins on a page can dynamically declare HTTP Vary headers (for example, utilizing the get_vary_cache_on() lifecycle hook to enforce client-specific rendering based on unique HTTP request headers), the internal server-side caching engine did not dynamically adapt its internal storage index lookup to match these changes.
This discrepancy creates an information isolation bypass. The server-side cache generates a static query index regardless of the dynamic variables declared by plugins, which allows unauthorized access to session-specific layouts, localized interface attributes, and access-restricted content. This behavior directly corresponds to CWE-524 (Use of Cache Containing Sensitive Information) and CWE-349 (Acceptance of Extraneous Untrusted Data with Trusted Data).
To understand the root cause of the flaw, it is necessary to examine how cache keys are resolved in cms/cache/page.py. In affected versions of django CMS, whenever a client requests a page, the application executes _page_cache_key(request) to find the associated storage index. This index computation is constructed by joining the designated cache prefix, the active site primary key, the resolved language identifier, the routing path, and optional timezone details.
When a page is rendered and subsequently stored via set_page_cache, django CMS evaluates the active plugins. If a plugin registers custom headers using get_vary_cache_on(), the application correctly executes Django's native utility patch_vary_headers to attach these fields to the outbound transport headers of the HTTP response. This action tells downstream browsers and intermediary CDN edge nodes to partition their caches based on those unique header values.
Despite the outbound transport header configuration, the internal database or caching mechanism does not adapt its local write logic. The rendered page is written to the server's backend under the static, header-agnostic identifier returned by _page_cache_key(request). Because of this omission, different incoming request states mapped to the exact same database string, causing the engine to read the first generated cache variant for all subsequent visitors regardless of their actual HTTP request headers.
The vulnerable code path is characterized by a static generation model within _page_cache_key. Reviewing the original implementation demonstrates that the function lacks parameter inputs to dynamically analyze request metadata variables:
# Vulnerable implementation in cms/cache/page.py
def _page_cache_key(request):
if hasattr(request, "LANGUAGE_CODE"):
language = request.LANGUAGE_CODE
else:
language = get_language_from_request(request)
# The generated lookup identifier is entirely blind to vary headers
cache_key = "\%s.\%s.\%s.\%s" \% (
settings.CMS_CACHE_PREFIX,
site.pk,
language,
path,
)
if settings.USE_TZ:
cache_key += ".\%s" \% get_timezone_name()
return cache_keyThe patch introduces a two-phase cache evaluation process to resolve this issue. First, a helper method _page_vary_headers_cache_key is established to retrieve the list of vary headers that have been registered for a given URL. Second, a sorting and normalization routine _vary_on_hash is introduced to create a SHA-1 hash of the active header values from the current request:
# Patched implementation in cms/cache/page.py
def _vary_on_hash(request, vary_on):
"""Computes an alphanumeric hash of specific request headers."""
ctx = hashlib.sha1()
for header in sorted(header.lower() for header in vary_on):
# Standardize WSGI headers from request.META
meta_key = "HTTP_" + header.upper().replace("-", "_")
value = request.META.get(meta_key, "")
ctx.update(("\%s=\%s&" \% (header, iri_to_uri(value))).encode("utf-8"))
return ctx.hexdigest()
def _page_cache_key(request, vary_on=None):
# Core identifiers are resolved here...
cache_key += ".\%s" \% _vary_on_hash(request, vary_on or [])
return cache_keyThis two-step process provides a robust defense against namespace collisions. On cache retrieval, the application checks the metadata key first to see what headers must be analyzed. If dynamic vary headers are found, the system hashes those active values from the incoming request to locate the correct, partitioned cache entry.
Exploiting this vulnerability requires specific deployment parameters. The primary attack vector involves Web Cache Poisoning, where an attacker alters the cached representation of a page for subsequent visitors. To accomplish this, the attacker identifies a page that changes its layout or content based on a custom header, such as X-User-Segment or Country-Code.
The attacker sends a request to the target page using malicious inputs in the target header. If the plugin's template renders this input directly, the application processes the malicious data. Because the cache key ignores the header values, the server-side cache stores this customized, corrupted response under the generic cache key. Any subsequent user who requests the page receives this poisoned response.
In an alternative scenario, an attacker can exploit the vulnerability to disclose sensitive, localized information. If a regional reverse proxy routes requests using custom headers, the attacker can query the page with regional values. By doing so, the attacker can force the server to cache regional layouts or configuration data under the public static cache key, exposing it to subsequent visitors from different geographical or administrative domains.
The confidentiality impact of this vulnerability is classified as Low. While user passwords or highly sensitive session tokens are not typically exposed via this cache path, the vulnerability can disclose regional configuration data, localized information segments, or context-specific data intended for other users.
The integrity impact of the vulnerability is significant. An attacker can poison the page cache to display manipulated or unauthorized content. If the application processes and reflects custom headers unsafely, an attacker could inject malicious scripts or cross-site scripting (XSS) payloads into the cached page, compromising the security of subsequent visitors.
The vulnerability is assessed with a CVSS v3.1 base score of 4.8. The high attack complexity reflects the specific configuration requirements, as the application must have CMS_PAGE_CACHE enabled and use plugins that utilize the get_vary_cache_on() interface. Because of these specific requirements, active exploit attempts are currently limited.
The primary remediation for this vulnerability is upgrading django CMS to a patched version. Administrators should upgrade stable production environments to version 5.0.8 or newer, and development environments to version 5.1.0 or newer. These updates introduce the dual-key cache resolution workflow, ensuring vary headers are correctly evaluated.
If an immediate upgrade is not possible, administrators can mitigate the vulnerability by disabling internal page caching in the project settings file:
CMS_PAGE_CACHE = FalseWhile disabling the cache protects the application from exploitation, it will increase database query volume and CPU usage on the application server. Administrators should monitor system performance closely if caching is disabled.
Additionally, administrators can configure upstream reverse proxies or CDNs to strip or sanitize custom headers from untrusted clients before the requests reach the application server. This prevents attackers from injecting custom values that could poison the cache.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
django-cms django CMS Association | < 5.0.8 | 5.0.8 |
django-cms django CMS Association | >= 5.1.0a1, < 5.1.0 | 5.1.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-524 / CWE-349 |
| Attack Vector | Network |
| CVSS v3.1 Score | 4.8 |
| EPSS Score | 0.00147 |
| Exploit Status | poc |
| KEV Status | Not Listed |
The product uses a cache that contains sensitive information, but it does not cleanly separate cached entries based on differences in authorization, identity, or dynamic attributes.
CVE-2026-109619 (PHP2Shell) is a critical Use-After-Free vulnerability in the core PHP engine caused by improper global state cleanup during out-of-memory exception handling across persistent worker requests.
In Python virtualenv prior to version 21.14.9, activation script generators and configuration writers use Path.exists() before writing files. Because Path.exists() resolves symbolic links, it returns False for dangling symlinks. Consequently, virtualenv skips unlinking pre-planted symbolic links or hard links, writing data directly to target locations outside the intended virtual environment directory.
A remote code execution vulnerability exists in Microsoft .NET due to untrusted data deserialization within the PresentationCore component. The flaw stems from implicit auto-conversion flags during clipboard data retrieval operations.
An out-of-bounds write vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio allows unauthenticated remote attackers to execute arbitrary code via crafted pixel-shader bytecode or auto-converted clipboard payloads.
ASP.NET Core contains a thread deadlock vulnerability (CWE-833) that allows an unauthenticated remote attacker to cause a denial of service over the network by exhausting server thread pool resources.
CVE-2026-70035 is a high-severity Remote Code Execution (RCE) vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio caused by improper handling during the deserialization of untrusted data (CWE-502). An unauthenticated attacker can execute arbitrary code within the context of the affected process by delivering a crafted serialized payload.