Aug 25, 2026·7 min read·2 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-55537 is a server-side request forgery (SSRF) and time-of-check time-of-use (TOCTOU) vulnerability in the PraisonAI multi-agent framework before version 4.6.58. The flaw exists in the job-submission component's webhook URL validation logic. When DNS resolution fails during verification, the application fails open, enabling attackers to register unresolvable URLs. When a completed job triggers the webhook, the application performs a fresh DNS resolution that attackers can manipulate to target internal resources.
A security vulnerability in the github.com/gorilla/websocket Go library allows remote attackers to predict client-to-server frame masking keys. This occurs because the library generates 32-bit mask keys using Go's non-cryptographically secure pseudo-random number generator (math/rand). Predicting these keys enables adversaries to bypass proxy-based security protections, facilitating HTTP request smuggling and cache poisoning attacks.
MHSanaei 3X-UI is a web control panel for managing Xray-core servers. In versions prior to 3.3.1, an authenticated administrator can abuse database import functions or raw template config fields to overwrite or append to arbitrary files on the host filesystem. This is achieved by altering the Xray log configuration variables to target system files, leveraging logging components to inject payloads.
Cloudreve is vulnerable to an incorrect authorization bypass. When listing files, Cloudreve returns a context_hint (represented as a UUID) to the client. If this context hint is replayed on the /file/url or /file/thumb routes, Cloudreve's database file system caches the shareNavigatorState containing the loaded share root. Within the cache lifetime (TTL of 300 seconds), if the user re-requests the same file with the cached hint, the system restores the state and completely bypasses the root security checks (which validate share expiration, remaining download limits, owner status, and passwords). This allows unauthorized users to continue generating signed file URLs and downloading files even after a share has been deleted, has expired, or has reached its download limit.
A path traversal vulnerability exists in Cloudreve's remote download workflow, where improper sanitization of file paths returned by configured remote downloaders (such as aria2) allows authenticated users to write files outside the designated target folder.
An integer overflow vulnerability exists in the HTTP/1.x chunked encoding parser of the vibeio-http library. The flaw is caused by unchecked integer addition when calculating the total buffer size required for processing parsed chunk lengths. By sending a maliciously crafted HTTP request containing an extremely large chunk size, an unauthenticated remote attacker can trigger a runtime panic, leading to complete denial of service.