---
id: "CVE-2026-61599"
page: "https://infrastack.ai/live/CVE-2026-61599"
kind: "vulnerability"
aliases: ["CVE-2026-61599", "GHSA-7prp-2623-8g45"]
title: "djust has an unauthenticated arbitrary module import via the WebSocket/SSE view-mount path"
severity: "high"
cvss: 8.8
epss: 0.00604
exploited: false
status: "open"
category: "package"
products: [{"name": "djust", "fixed": ["1.0.7"], "affected": "< 1.0.7", "ecosystem": "pypi"}]
ecosystems: ["pypi"]
tags: ["cwe-470", "django", "djust", "package", "python", "sse", "websocket"]
not_affected_if: ["djust-not-installed", "live-transport-not-exposed", "version-1.0.7-or-later"]
published_at: "2026-09-16T22:09:38+00:00"
first_seen_at: "2026-11-05T23:02:16+00:00"
updated_at: "2026-11-05T23:15:56+00:00"
sources: [{"source": "ghsa", "url": "https://github.com/advisories/GHSA-7prp-2623-8g45", "first_seen_at": "2026-11-05T23:02:16+00:00"}, {"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-61599", "first_seen_at": "2026-11-05T23:15:56+00:00"}]
exploit_sources: [{"type": "epss", "score": 0.00604, "url": "https://api.first.org/data/v1/epss?cve=CVE-2026-61599"}]
---

# djust has an unauthenticated arbitrary module import via the WebSocket/SSE view-mount path

Link for people: https://infrastack.ai/live/CVE-2026-61599 (this .md is for agents)

djust resolves a client-supplied dotted view path with __import__ before checking authentication or that the object is a LiveView, so the module's top-level code runs. An unauthenticated client can therefore execute import-time code of any importable Python module, and can also use error messages to enumerate modules.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- pypi:djust affected < 1.0.7 fixed 1.0.7

## How to check

- Check the installed djust version with `pip show djust` and compare it to the fixed range.
- Check the Django settings for `LIVEVIEW_ALLOWED_MODULES`; if it is unset, the allowlist is fail-open.
- Look for WebSocket or SSE routes that serve djust LiveViews in publicly reachable deployments.

## Fix

- djust: upgrade to `1.0.7` or later (affected versions are below `1.0.7`).
- Workaround until upgraded: set `LIVEVIEW_ALLOWED_MODULES` to the narrow list of modules that contain your mountable LiveView classes; the sources say this is mitigation, not a complete fix.

## Timeline

- 2026-11-05T23:02:16+00:00 ghsa https://github.com/advisories/GHSA-7prp-2623-8g45
- 2026-11-05T23:15:56+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-61599

## Documents

- [advisory] Maintainer's advisory: api.github.com https://api.github.com/repos/djust-org/djust/security-advisories/GHSA-7prp-2623-8g45
- [advisory] Maintainer's advisory: github.com https://github.com/djust-org/djust/security/advisories/GHSA-7prp-2623-8g45
- [fix] Release: github.com https://github.com/djust-org/djust/releases/tag/v1.0.7
- [fix] Patch: github.com https://github.com/djust-org/djust/commit/04985e2f6a69faf265fc512b323d28adaa15c3ff

## From the sources

### Impact
The djust live transport resolves the LiveView to mount from a **client-supplied dotted path** by calling `__import__(module_path, ...)`. The module is imported — running its **top-level code (import side effects)** — *before* the framework checks that the resolved object is a `LiveView` subclass and *before* any per-view authentication. The `LIVEVIEW_ALLOWED_MODULES` allowlist that should contain this is **fail-open** (`if allowed_modules:` — skipped when the setting is unset, the framework default) and uses loose `startswith` matching.

An **unauthenticated** WebSocket client (the WS handshake does not require auth; per-view auth runs only after import + instantiate) can therefore send a `mount` / `live_redirect_mount` / `url_change` frame (or an SSE mount) with `view = "<any.importable.module>.AnyName"` and cause the server to import — and execute the top-level code of — **any importable Python module by name**.

**Consequences:** server-side execution of arbitrary importable modules' import-time side effects by an unauthenticated client (effectively RCE-by-proxy on any host that has a side-effectful importable module), denial of service (import bombs / expensive dependency trees), and a module/class **enumeration oracle** via distinct error strings.

Reproduced end-to-end: an unauthenticated `WebsocketCommunicator` `mount` frame with the allowlist unset imported and executed a sentinel non-LiveView module before the "not a LiveView subclass" rejection.

### Affected code
- `python/djust/websocket.py` `handle_mount` (`__import__` of the client `view`)
- `python/djust/runtime.py` `ViewRuntime.dispatch_mount` / `_instantiate_view` (SSE + `url_change` path)
- `python/djust/sse.py` SSE mount

Threat-model entry T4 (`docs/audits/websocket-auth-2026-06.md`) previously noted the default-open allowlist but understated the impact as mere LiveView-class probing; the real primitive is arbitrary-module import + top-level code execution, independent of whether the target is a LiveView.

### Patches
Fixed by a fail-**closed** resolution gate (`djust._view_resolution.is_view_import_allowed`): a client view path resolves only if (a) its module is **already loaded** (`sys.modules` — so resolving runs no new code; URL-routed views loaded by URLconf at startup keep working with zero config) or (b) it matches `LIVEVIEW_ALLOWED_MODULES` on a **module-segment boundary** (explicit opt-in for lazily-imported views). The gate runs **before** `__import__` at all three sinks (+ defense-in-depth inside `_instantiate_view`).

### Workarounds
Set `LIVEVIEW_ALLOWED_MODULES` to the narrow list of modules that contain your mountable LiveView classes. (Note: pre-patch the allowlist is `startswith`-matched and the import still precedes the subclass check, so this is mitigation, not a complete fix.)

### References
Reproducer + finding writeup retained privately by the maintainer.

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
