CVE-2026-61595
nicheCross-tenant data disclosure in djust via fail-open tenant isolation on WebSocket/SSE
The multi-tenancy module (djust.tenants) in djust enforced tenant isolation only on the HTTP request path: the current tenant was stored in threading.local() and set exclusively by the HTTP-only TenantMiddleware, so on live WebSocket/SSE connections get_current_tenant() returned None during mount and in every event handler. Because the tenant-aware QuerySet manager failed OPEN in that situation — returning the unfiltered queryset even when STRICT_MODE was enabled — any query issued over the live path returned rows from every tenant. An attacker with a low-privilege account in one tenant who holds a WebSocket/SSE connection can therefore read other tenants' data (high confidentiality impact, no integrity or availability impact; CVSS 3.1 score 7.7 with scope change). All deployments running djust versions before 1.0.7 that use the djust.tenants feature together with WebSocket/SSE live connections are affected; plain HTTP-only usage is not impacted. No public proof-of-concept, KEV listing, or in-the-wild exploitation is known, and fixed version 1.0.7 is available.
What to do: Upgrade to djust 1.0.7 immediately, as there is no workaround for the live WebSocket/SSE path. Keep STRICT_MODE enabled (the default) and resolve any system check S006 warnings if STRICT_MODE was disabled; after patching, review access logs for suspicious cross-tenant reads performed over WebSocket/SSE connections.
| djust (PyPI project) djust | all versions prior to 1.0.7 (when the djust.tenants multi-tenancy feature is used with WebSocket/SSE live paths) |
Order-of-magnitude estimate by the model from install counts, market share and public scan data it knows; verify before quoting.
djust provides Phoenix LiveView-style reactive server-side rendering for Django with Rust-powered performance. Prior to version 1.0.7, `djust.tenants` isolation was enforced only on the HTTP path. The current tenant was stored in `threading.local()` and set exclusively by the HTTP-only `TenantMiddleware`, so on the live (WebSocket/SSE) path `get_current_tenant()` was always `None` during mount and every event handler — and the tenant-aware `QuerySet` manager failed OPEN (returned the unfiltered queryset, ignoring `STRICT_MODE`), disclosing every tenant's rows to whoever held the socket. `threading.local` was additionally shared across connections on the `sync_to_async` executor thread. This issue is fixed in djust 1.0.7. Tenant storage moved to a `contextvars.ContextVar` (per async task); the resolved tenant is bound around WS/SSE mount and every dispatch; both managers scope the base queryset once and fail CLOSED (`.none()` under the default `STRICT_MODE`); and system check S006 warns when `STRICT_MODE=False`. No known workarounds are available on the live path.
- Ecosystems
- pip
- Weakness
- CWE-636, CWE-862
- Vector
- CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
- GHSA
- GHSA-3492-cvg7-9mr2 (high)
In the news0 stories
No ingested article mentions this CVE yet.