Sep 17, 2026·6 min read·3 visits
The djust framework prior to 1.0.7 accepted client-supplied session IDs in the Server-Sent Events (SSE) transport without verifying user ownership, enabling session hijacking and unauthorized state execution.
A high-severity session hijacking and authorization bypass vulnerability has been identified in the djust framework prior to version 1.0.7. The flaw resides in the Server-Sent Events (SSE) transport implementation, which keyed sessions solely by client-provided session identifiers without verifying session ownership or binding. This allows an attacker who possesses or guesses a victim's session identifier to send malicious post messages to execute arbitrary state machine event handlers under the identity and permissions of the victim.
The djust framework provides high-performance, reactive server-side rendering for Django applications, utilizing a Rust-optimized state machine to mirror UI and session states. The application supports two main underlying transports: WebSockets and Server-Sent Events (SSE). While the WebSocket implementation enforces strict, stateful authentication mapping, the SSE transport failed to implement equivalent authorization boundaries.\n\nBecause Server-Sent Events operate over stateless unidirectional streams paired with standard HTTP POST requests, the framework tracks session states on the server using an arbitrary key. Prior to version 1.0.7, this key was chosen and supplied directly by the client client-side without cryptographic verification. This structural gap exposes an unauthenticated attack surface to remote attackers, registered under the Common Weakness Enumeration as CWE-384 and CWE-862.\n\nIf an attacker can acquire, guess, or intercept an active client-chosen session identifier, they can issue arbitrary state manipulation calls. The server will process the event handlers inside the memory context of the victim's session. The execution context operates with the target victim's privileges, bypassing the identity check completely.
The root cause of this vulnerability lies in the stateless nature of SSE connections and how the framework manages its virtual DOM (VDOM) state machine index. When a user navigates to a reactive page, the server allocates a session state mapped to a unique session_id. However, in versions prior to 1.0.7, the framework relied entirely on a client-declared string value rather than an immutable, cryptographically generated token issued exclusively by the server.\n\nFurthermore, the message dispatcher endpoint /djust/api/message/ processed state mutations without validating the requesting principal's identity. The endpoint merely matched the incoming session_id payload to the corresponding backend state machine in memory. If a match was found, the endpoint executed the requested event handler within that state context.\n\nConsequently, there was no server-side validation to check whether the authenticated Django user (request.user) initiating the POST request matched the authenticated user who initially established the SSE channel. This lack of binding enables an attacker to perform cross-principal state hijacking by submitting POST commands with a stolen or predicted identifier.
An examination of the vulnerable code path reveals that the dispatcher accepted client-supplied arguments directly. Below is a conceptual illustration of the vulnerable dispatcher logic compared with the remediated framework implementation.\n\npython\n# Vulnerable SSE message dispatcher (Pre-1.0.7)\ndef handle_sse_message(request):\n payload = json.loads(request.body)\n session_id = payload.get(\"session_id\")\n \n # Retrieving state context purely by user-controlled key\n session_state = state_manager.get_session(session_id)\n if not session_state:\n return JsonResponse({\"error\": \"Session not found\"}, status=404)\n \n # CRITICAL: No validation of request.user against session creator\n event = payload.get(\"event\")\n handler = payload.get(\"handler\")\n result = session_state.dispatch_event(event, handler, payload.get(\"payload\"))\n return JsonResponse({\"status\": \"success\", \"result\": result})\n\n\nThe patch implemented in version 1.0.7 introduces explicit user principal binding. The framework now stores the owner's identity upon session initialization and enforces an explicit validation check on each incoming message.\n\npython\n# Remediation and principal binding (v1.0.7)\ndef handle_sse_message(request):\n payload = json.loads(request.body)\n session_id = payload.get(\"session_id\")\n \n session_state = state_manager.get_session(session_id)\n if not session_state:\n return JsonResponse({\"error\": \"Session not found\"}, status=404)\n \n # PATCH RESOLUTION: Validate principal identity of incoming request\n if session_state.owner_id != request.user.id:\n logger.warning(f\"Unauthorized session access: User {request.user.id} tried accessing {session_id}\")\n return JsonResponse({\"error\": \"Unauthorized session access\"}, status=403)\n \n event = payload.get(\"event\")\n handler = payload.get(\"handler\")\n result = session_state.dispatch_event(event, handler, payload.get(\"payload\"))\n return JsonResponse({\"status\": \"success\", \"result\": result})\n\n\nThis verification check successfully closes the vulnerability window. By validating owner_id against request.user.id, the server prevents any unauthenticated or unauthorized users from executing events on active reactive sessions.
Exploitation of this vulnerability requires that the target application has the Server-Sent Events (SSE) transport enabled and that the attacker has acquired a valid session_id. Attackers can potentially acquire the target ID via diagnostic log files, local cache directories, local storage access (via cross-site scripting), or predictive guessing if the identifier generation lacks sufficient entropy.\n\nOnce the attacker obtains the valid identifier, they can construct a direct HTTP POST request targeting the message execution endpoint. The attacker does not need to bypass the standard Django authentication cookies of the target user, since the dispatcher executes the logic based on the matched state memory of the active SSE session.\n\nhttp\nPOST /djust/api/message/ HTTP/1.1\nHost: vulnerable-application.com\nContent-Type: application/json\n\n{\n \"session_id\": \"victim_session_id_xyz\",\n \"event\": \"click\",\n \"handler\": \"execute_payment\",\n \"payload\": {\n \"recipient\": \"attacker_account\",\n \"amount\": 5000\n }\n}\n\n\nUpon receipt of the payload, the vulnerable backend state machine executes the execute_payment handler in the context of the user session associated with victim_session_id_xyz. The server then processes the transaction, allowing the attacker to conduct actions under the victim's identity.
The technical impact of CVE-2026-61592 is severe, compromising both confidentiality and integrity of active sessions within the application. An attacker can hijack the state machine of any user on the platform, allowing complete read access to state structures and write access to trigger form actions, administrative endpoints, or transactional logic.\n\nThe Common Vulnerability Scoring System (CVSS) base score is 7.4 (High). The attack vector is Network (AV:N), and user interaction is not required (UI:N). The attack complexity is assessed as High (AC:H) because the attacker must first discover an active, valid session identifier through separate channels before executing commands.\n\nAt the time of this analysis, there are no documented instances of active exploitation in the wild, nor has any weaponized exploit payload been observed. However, due to the direct route to authorization bypass, systems employing the SSE transport of djust remain highly exposed until patched.
The definitive remediation is upgrading the djust package to version 1.0.7 or later, which implements secure session-to-principal bindings. The upgrade can be performed using standard Python package management tools.\n\nbash\npip install --upgrade djust>=1.0.7\n\n\nIf an immediate upgrade is not feasible, operators must apply a temporary workaround by disabling the SSE transport layer in the application configuration. This forces the application to fallback entirely to the secure WebSocket transport. Ensure that WebSockets are properly supported by your load balancers and proxy servers before applying this configuration change.\n\npython\n# Django settings.py mitigation example\nDJUST_SSE_ENABLED = False\n\n\nSecurity teams should also review application logs for requests directed to /djust/api/message/ containing identical session_id values but originating from distinct IP addresses or bearing different Django session cookies.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
djust djust-org | < 1.0.7 | 1.0.7 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-384 / CWE-862 |
| Attack Vector | Network |
| CVSS Score | 7.4 |
| EPSS Score | 0.00 |
| Impact | Session Hijacking / Privilege Escalation |
| Exploit Status | none |
| KEV Status | not listed |
The application lacks proper authorization checks on SSE event-handling requests, allowing attackers to access stateful sessions using user-controlled session identifiers.
Prior to version 1.0.7, the djust Python package is vulnerable to Stored and Reflected Cross-Site Scripting (XSS) via component template tags. The underlying issue exists because the package fails to sanitize or validate incoming URI schemes when rendering URLs inside interactive HTML attributes like href or action. While the framework HTML-escapes strings to prevent attribute breakout, it permits the execution of arbitrary JavaScript via the javascript: pseudo-protocol.
CVE-2026-61591 is a high-severity state injection and authorization bypass vulnerability affecting the djust framework's opt-in State Snapshot feature. Prior to version 1.0.7, the framework restored public view state snapshots returned from the client browser during back-navigation without validating their cryptographic authenticity or integrity. This flaw allows malicious clients to manipulate serialized JSON payloads to inject unauthorized properties, leading to mass assignment (CWE-915) and privilege escalation. Version 1.0.7 addresses this issue by introducing HMAC cryptographic signatures bound to both the view configuration and the user's session identifier.
A critical connection reuse vulnerability exists in curl and libcurl between versions 7.64.1 and 8.21.0 inclusive when Negotiate authentication (SPNEGO) is configured with blank credentials. Because libcurl fails to track changes to the underlying operating system's ambient security context, persistent authenticated connections are incorrectly matched and shared between distinct user sessions, allowing subsequent users to execute requests with the authorization state of the prior user.
A sensitive data exposure vulnerability exists in the djust framework before version 1.0.7. When serializing Django models to public view attributes, the framework fails to filter out sensitive fields such as passwords, privilege flags, and private tokens, leading to over-serialization and exposure of sensitive records to the client browser.
A broken object-level access control (IDOR) vulnerability exists in the djust Django framework prior to version 1.0.7. The framework's per-object authorization hooks were enforced correctly over WebSockets but entirely bypassed on synchronous HTTP GET rendering, SPA client-side navigation, and embedded sub-views, allowing authenticated attackers to view arbitrary unauthorized database records.
CVE-2026-61589 is a security-bypass and information-disclosure vulnerability in the djust library prior to version 1.0.7. The library's WebSocket live path component fails to propagate the client HTTP Host header when dynamically reconstructing Django HttpRequest objects. Consequently, multi-tenant Django applications that rely on Host-based resolution may fail to isolate data correctly under certain configurations, leading to unauthorized cross-tenant data access.