PT-2026-105795 · Pypi · Djust
Published
2026-10-01
·
Updated
2026-10-01
CVSS v4.0
8.8
High
| Vector | AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:H/VA:L/SC:N/SI:N/SA:N |
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.pyhandle mount(importof the clientview)python/djust/runtime.pyViewRuntime.dispatch mount/instantiate view(SSE +url changepath)python/djust/sse.pySSE 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.
Fix
Found an issue in the description? Have something to add? Feel free to write us 👾
Related Identifiers
Affected Products
Djust