CVE-2026-55571 Overview
CVE-2026-55571 is an authorization bypass vulnerability in djust, a Django library that provides Phoenix LiveView-style reactive server-side rendering with Rust-powered performance. Versions prior to 1.0.4 fail to close the WebSocket connection when authentication or authorization checks deny a LiveView mount. A raw WebSocket client can ignore the redirect frame and continue sending event frames against the still-mounted socket. The LiveViewConsumer.handle_event method does not re-check authentication, allowing unauthenticated invocation of @event_handler methods. This flaw maps to CWE-285: Improper Authorization.
Critical Impact
Unauthenticated network attackers can invoke server-side event handlers reserved for authorized users, enabling sensitive reads and mutations without a valid session.
Affected Products
- djust versions prior to 1.0.4
- Django applications using LiveViewConsumer with login_required decorators
- Django applications using permission_required or redirecting on_mount hooks
Discovery Timeline
- 2026-08-25 - CVE-2026-55571 published to NVD
- 2026-08-25 - Last updated in NVD database
Technical Details for CVE-2026-55571
Vulnerability Analysis
The vulnerability resides in LiveViewConsumer.handle_mount within python/djust/websocket.py. When login_required, permission_required, or a redirecting on_mount hook denies mount, the consumer emits a JSON frame of the form {"type":"navigate","to":<redirect_url>} and then returns. The consumer does not call close() on the WebSocket and does not reset self.view_instance. Browsers honor the redirect and disconnect, masking the flaw in normal use.
A raw WebSocket client such as websocat or a custom script can ignore the navigate frame and hold the socket open. Because handle_event performs no session or permission re-check, subsequent {"type":"event",...} frames dispatch to @event_handler methods bound to the view. The handle_live_redirect_mount path can also be reached, broadening the exposed surface. The result is anonymous invocation of handlers intended for authenticated, authorized users.
Root Cause
The root cause is a missing socket-close and state-clear on the auth-denied branch, combined with the absence of authorization re-validation inside the event dispatch path. Authorization was assumed to be enforced solely at mount time, so handle_event trusted self.view_instance without re-checking session state.
Attack Vector
Exploitation requires network reachability to the Django Channels WebSocket endpoint. An attacker connects without credentials, receives the navigate frame, discards it, and sends crafted event frames referencing the target view's event handlers. Depending on handler logic, this leads to unauthorized data reads or state-changing mutations.
await self.close(code=4403)
return
if redirect_url:
+ # Auth failure (e.g. anonymous user on a login_required view).
+ # Send the redirect frame so a browser navigates to LOGIN_URL,
+ # THEN close the socket — otherwise a raw WS client can ignore
+ # the navigate and keep sending events to handlers with no
+ # authenticated session (the mount left view_instance set but
+ # never ran mount(), and handle_event does not re-check auth).
+ # Mirrors the PermissionDenied/4403 branch above. (Threat model
+ # T1, docs/audits/websocket-auth-2026-06.md.)
await self.send_json(
{
"type": "navigate",
"to": redirect_url,
}
)
+ # Clear the unmounted view so handle_event can't dispatch against
+ # it, then close — UNLESS we're inside a multiplexed mount_batch
+ # on a shared socket, where the navigate frame is collected into
+ # navigate[] and closing would kill sibling mounts (the batch
+ # reports this view as a redirect, not a bypass). (T1)
+ self.view_instance = None
+ if not getattr(self, "_mounting_in_batch", False):
+ await self.close(code=4403)
return
# --- End auth check ---
Source: GitHub Commit 1ae8aa9. The patch closes the socket with code 4403 and nulls self.view_instance on the redirect branch, preventing subsequent event dispatch.
Detection Methods for CVE-2026-55571
Indicators of Compromise
- WebSocket sessions that receive a {"type":"navigate"} frame from the server but remain open and continue sending client frames.
- Inbound {"type":"event",...} frames from clients whose Django session is anonymous or lacks the required permission for the target view.
- Repeated event traffic against LiveView endpoints originating from non-browser User-Agent strings.
Detection Strategies
- Instrument LiveViewConsumer to log every event dispatch with the associated user identity and view name, then alert when identity is anonymous.
- Correlate ASGI access logs with authentication logs to flag WebSocket sessions active for users with no successful login within the session window.
- Deploy application-layer WAF or reverse-proxy rules that terminate WebSocket connections when the server issues a navigate frame in response to a mount.
Monitoring Recommendations
- Monitor WebSocket close codes; a sharp drop in 4403 closures after a patch rollback may indicate regression.
- Track event-handler invocation rates per view and alert on anomalous invocation from unauthenticated sessions.
- Ingest Django Channels logs into a centralized data lake to enable retroactive hunting for pre-patch abuse.
How to Mitigate CVE-2026-55571
Immediate Actions Required
- Upgrade djust to version 1.0.4 or later across all Django deployments.
- Audit application logs for event frames received after a navigate frame was issued on the same socket.
- Rotate any secrets or tokens exposed through affected @event_handler methods if abuse is confirmed.
Patch Information
The fix ships in djust v1.0.4 via Pull Request #1780. Full technical detail is available in GHSA-xx4j-w367-7247. The patch clears self.view_instance and closes the socket with code 4403 on the auth-redirect branch, except when a multiplexed mount_batch is in progress.
Workarounds
- Add an explicit authentication and authorization check at the top of every @event_handler method until the upgrade is deployed.
- Place a reverse proxy in front of the ASGI server to force-close WebSocket connections after a server-originated navigate frame.
- Restrict WebSocket endpoints to authenticated sessions at the ingress layer where feasible.
# Upgrade djust to the patched release
pip install --upgrade 'djust>=1.0.4'
# Verify the installed version
python -c "import djust; print(djust.__version__)"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

