CVE-2026-61599: djust has an unauthenticated arbitrary module import via the WebSocket/SSE view-mount path
### 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.
Recommended action
Recommended action
Upgrade affected packages to a patched version: djust 1.0.7.
Technical details
- Vendor
- Not specified
- Product
- djust
- Exploitation
- none known
- Evidence
- official
Evidence and sources
This record is attributed to GitHub Advisories. Exploitation status and remediation guidance are kept separate from the vulnerability's technical severity.
Open primary source