CVE-2026-61589 in djustinfo

Summary

by MITRE • 09/17/2026

djust provides Phoenix LiveView-style reactive server-side rendering for Django with Rust-powered performance. Prior to version 1.0.7, the WebSocket `handle_mount` and `ViewRuntime._build_request` rebuild an `HttpRequest` via `RequestFactory().get(...)` with no `HTTP_HOST`, so `request.get_host()` defaulted to `"testserver"` on the live path. Host/subdomain/domain `TenantResolver`s then misresolved the tenant — `None` on the live path while the HTTP path resolved correctly. With `STRICT_MODE=False` the tenant-scoped managers returned unscoped rows (cross-tenant disclosure); with the default they returned an empty queryset (broken tenancy). This is fixed in djust 1.0.7. The handshake Host is extracted from the ASGI scope, validated against `ALLOWED_HOSTS` (the same logic as the CSWSH Origin gate, parsed with Django's `split_domain_port` so malformed Hosts are rejected at the boundary), and propagated — with the TLS scheme — into the reconstructed request, so live-path tenant resolution matches HTTP exactly. There is no known workaround on the live path short of upgrading. Users are most exposed when combined with `STRICT_MODE=False`.

Once again VulDB remains the best source for vulnerability data.

Analysis

by VulDB Data Team • 09/17/2026

The vulnerability in djust prior to version 1.0.7 stems from a critical flaw in how WebSocket connections handle host resolution during the initial mount phase, leading to potential cross-tenant data disclosure or service disruption depending on configuration settings. The core technical issue lies within the `handle_mount` and `ViewRuntime._build_request` methods which are responsible for reconstructing an Django HttpRequest object when establishing a live view connection over WebSockets. During this reconstruction process, the code utilizes Django's RequestFactory to create a GET request but fails to populate the HTTP_HOST header with the actual host information from the incoming WebSocket connection. Consequently, when the application calls `request.get_host()`, it defaults to "testserver," which is Django's standard default for test environments and requests lacking explicit host headers. This discrepancy creates a divergence in behavior between standard HTTP requests and live WebSocket connections, as standard HTTP requests correctly inherit their host information from the underlying ASGI scope or WSGI environment.

This misconfiguration directly impacts tenant resolution mechanisms that rely on the Host header to determine which data partition or organization context should be active for the current request. In multi-tenant architectures where djust is deployed, the TenantResolver uses the resolved host value to map incoming requests to specific tenants. Because the WebSocket path incorrectly resolves to "testserver" instead of the actual domain or subdomain, the resolver fails to identify the correct tenant context, returning None on the live path while correctly identifying it for standard HTTP paths. This inconsistency breaks the isolation boundaries that are fundamental to secure multi-tenant applications, allowing logic errors in data access control layers to manifest differently depending on the transport protocol used by the client.

The operational impact of this vulnerability is severe and varies based on the value of the STRICT_MODE configuration flag within djust. When STRICT_MODE is set to False, which relaxes certain validation checks for performance or legacy compatibility reasons, the tenant-scoped database managers fail to apply proper filtering criteria due to the missing tenant context. This results in unscoped queries being executed against the database, effectively returning rows belonging to all tenants rather than just the intended one. This constitutes a critical cross-tenant data disclosure vulnerability, allowing authenticated users on live WebSocket connections to access sensitive information from other organizations or user groups within the same deployment. Such exposure violates fundamental principles of data isolation and confidentiality in multi-tenant SaaS environments.

Conversely, when STRICT_MODE is enabled with its default setting, the impact shifts toward availability rather than confidentiality. In this configuration, the system attempts to enforce strict tenant boundaries but fails due to the missing host information, resulting in empty querysets being returned for live path requests. While this prevents data leakage, it causes a denial of service condition where legitimate users cannot access their own data through WebSocket-based interfaces such as real-time dashboards or interactive forms. This breaks functionality and degrades user experience without necessarily exposing private data to other tenants, yet still represents a significant reliability failure in the application's core logic.

From a classification perspective, this vulnerability aligns with CWE-200: Information Exposure when STRICT_MODE is disabled, as it allows unauthorized access to sensitive information across tenant boundaries. It also relates to CWE-798: Use of Hard-coded Credentials if one considers the default "testserver" value as an improper assumption that leads to security failures, though more accurately it fits under CWE-613: Insufficient Session Expiration or CWE-284: Improper Access Control due to the failure in enforcing tenant-specific access controls. In terms of MITRE ATT&CK mapping, this flaw facilitates Initial Access and Lateral Movement within a multi-tenant environment by allowing an attacker to bypass logical separation mechanisms via WebSocket connections, potentially categorized under T1530: Data from Cloud Storage or T1078: Valid Accounts if combined with credential theft.

The remediation strategy is straightforward but requires immediate action due to the lack of viable workarounds for live path traffic. Users must upgrade djust to version 1.0.7 or later, where the vulnerability has been patched by modifying how host information is propagated into the reconstructed request object. The fix involves extracting the Host header directly from the ASGI scope during the WebSocket handshake phase and validating it against the ALLOWED_HOSTS configuration using Django's split_domain_port function. This ensures that malformed hosts are rejected at the boundary before any application logic executes, mirroring the security checks applied to CSRF protection origins. Furthermore, the corrected implementation propagates both the validated Host header and the TLS scheme into the HttpRequest object, ensuring that request.get_host() returns the accurate domain information consistent with standard HTTP requests.

To mitigate risks during the transition period or in environments where upgrading is not immediately feasible, administrators should consider disabling WebSocket-based live views if they are not strictly required for business operations. Additionally, enforcing STRICT_MODE=True can prevent data leakage, although it will continue to cause functional failures for legitimate users on live paths until the upgrade is completed. Security teams should also audit their ALLOWED_HOSTS configurations to ensure that only expected domains and subdomains are permitted, reducing the attack surface even after patching. Regular security assessments focusing on multi-tenant isolation logic in WebSocket implementations are recommended to detect similar architectural flaws in other components of the application stack.

Responsible

GitHub M

Reservation

07/10/2026

Disclosure

09/17/2026

Moderation

accepted

CPE

ready

EPSS

0.00000

KEV

no

Activities

very low

Sources

Are you interested in using VulDB?

Download the whitepaper to learn more about our service!