CVE-2026-55571: djust LiveView WebSocket Authentication Bypass
A flaw in djust's LiveView WebSocket consumer lets an unauthenticated attacker skip a login redirect and call protected server-side event handlers, bypassing all access controls on gated views.

The problem
djust's LiveViewConsumer mounts LiveViews over a persistent WebSocket. When a view is protected by login_required, permission_required, or a redirecting on_mount hook, the consumer sent the client a {"type":"navigate"} redirect frame and returned early, but it did NOT close the socket and did NOT clear self.view_instance.
A real browser obeys the navigate frame and disconnects. A raw WebSocket client that ignores the redirect keeps a live, fully mounted socket. Because handle_event never re-checked auth after mount, that client could then send {"type":"event"} frames and invoke any @event_handler on the gated view with zero authentication.
Only the PermissionDenied branch correctly called close(4403). The auth-redirect and on-mount-redirect branches did not.
Proof of concept
A working proof-of-concept for CVE-2026-55571 in djust, with the exact payload below.
# 1. Connect as anonymous over WebSocket to a login_required view
# Use Django Channels' WebsocketCommunicator or any raw WS client
# Step 1 — mount the gated view (server replies with navigate frame, but socket stays open)
connect_msg = {
"type": "mount",
"path": "/dashboard/" # any login_required LiveView path
}
# Step 2 — server sends redirect but does NOT close the socket:
# {"type": "navigate", "to": "/accounts/login/?next=/dashboard/"}
# Ignore it. Socket is still open and self.view_instance is still set.
# Step 3 — send an event frame to invoke a protected handler
event_msg = {
"type": "event",
"handler": "delete_record", # any @event_handler on the gated view
"payload": {"id": 1}
}
# Handler executes with no authenticated session on djust < 1.0.4The root cause is a missing close() call after the auth-redirect branch in handle_mount. The PermissionDenied branch already called close(code=4403) and cleared self.view_instance, but the login_required / permission_required / on_mount-redirect branches only sent the navigate frame and returned, leaving the socket alive with the view fully instantiated.
Because handle_event trusted that a mounted socket implied an authorized session, it routed incoming {"type":"event"} frames directly to the decorated handler with no second auth check. The patch (commit 1ae8aa9, PR #1780) makes all redirect-triggering branches call close(code=4403) and clear self.view_instance immediately after sending the navigate frame, matching the behavior of the existing PermissionDenied path.
The optional LIVEVIEW_CONFIG['reauth_on_event'] = True setting added in 1.0.4 provides defense-in-depth by re-resolving the user from the session and re-running the view's auth check on every event dispatch for gated views (default off).
The fix
Upgrade to **djust 1.0.4** (commit 1ae8aa9, PR #1780). If an immediate upgrade is not possible, add an explicit auth check at the top of every @event_handler on gated views (request.user.is_authenticated / permission check), or override handle_mount to call await self.close(code=4403) after any auth redirect.
After upgrading, consider enabling LIVEVIEW_CONFIG['reauth_on_event'] = True for defense-in-depth on sensitive views.
Related research
- critical · 9.1CVE-2026-55640CVE-2026-55640: nextcloud-mcp-server Unauthenticated Webhook Allows Arbitrary Vector Data Deletion
- high · 8.6CVE-2026-55539CVE-2026-55539: PraisonAI Jobs API Missing Authentication
- high · 7.3CVE-2026-55538CVE-2026-55538: PraisonAI serve agents --api-key Authentication Bypass
- high · 8.2CVE-2026-55528CVE-2026-55528: praisonaiagents AgentServer Missing Authentication