Sep 17, 2026·7 min read·8 visits
djust prior to 1.0.7 leaks sensitive database fields (such as user password hashes and administrator flags) to the browser when Django models are bound directly to public LiveView attributes.
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.
The djust framework is a high-performance web development library that enables Phoenix LiveView-style reactive server-side rendering for Django applications. By utilizing bidirectional connections over WebSockets or Server-Sent Events, the framework maintains state synchronization between the server and client-side Virtual DOM. Developers declare state attributes on a LiveView instance, and any public attribute is automatically serialized and sent to the client to render updates.
Prior to version 1.0.7, a critical flaw existed in the default serialization engine of djust. When a developer assigned a standard Django database Model instance to a public view attribute, the entire model object was serialized without any filtering of sensitive fields. This resulted in the inadvertent transmission of highly sensitive data, such as hashed user credentials, authentication tokens, and administrative privilege indicators directly to the browser.
This behavior created a broad, implicit attack surface because binding database models to view attributes is a standard pattern in modern reactive web architectures. The vulnerability is classified under CWE-200 (Exposure of Sensitive Information to an Unauthorized Actor) and CWE-359 (Exposure of Private Personal Information). It presents a significant risk to applications built on older djust versions that expose user profiles or core domain models to interactive templates.
The root cause of CVE-2026-61588 lies within the _serialize_model_safely helper function, which was invoked by the custom DjangoJSONEncoder inside djust's state-synchronization engine. When a public attribute on a LiveView was identified as a Django Model instance, the encoder recursively extracted values for all concrete database columns. The implementation lacked any form of field-filtering or authorization-aware validation before assembling the JSON payload.
This flaw was exacerbated by the multi-channel synchronization design of djust. Specifically, there are three primary paths through which over-serialization occurred. The first is active state synchronization (get_state()), where state updates are periodically computed and transmitted as delta packages. The second is state-snapshotting (enable_state_snapshot = True), which serializes the current view state directly into hidden elements within the static HTML structure to facilitate state recovery. The third path is the JIT compiler's fallback mode, which executes a complete object-level serialization if a model is referenced as a whole within the template or when an attribute is declared public but not parsed on a granular property level.
Because the framework prioritized seamless data accessibility over strict boundary controls, it operated on an implicit 'allow-all' model. Consequently, properties like password (holding PBKDF2 or bcrypt hashes), is_superuser, is_staff, and custom business tokens (such as API keys or personal identifiers) were converted into plaintext JSON properties and placed directly onto the websocket stream.
The security update in version 1.0.7 completely refactored the serialization process to introduce structured, multi-tier protection. Below is a conceptual demonstration of the vulnerable implementation versus the secure implementation in _serialize_model_safely:
# VULNERABLE: djust < 1.0.7
def _serialize_model_safely(model_instance):
# Iterates and serializes every concrete database field without restriction
data = {}
for field in model_instance._meta.concrete_fields:
data[field.name] = field.value_from_object(model_instance)
return data# PATCHED: djust >= 1.0.7
def _serialize_model_safely(model_instance):
# 1. Check if model provides custom serialization representation
if hasattr(model_instance, 'to_dict'):
return model_instance.to_dict()
# 2. Establish hardcoded security floor
built_in_denylist = {'password', 'is_superuser', 'is_staff'}
global_denylist = getattr(settings, 'DJUST_SENSITIVE_FIELDS', set())
merged_denylist = built_in_denylist.union(global_denylist)
# 3. Handle model-level allowlists or exclusion lists
model_excludes = getattr(model_instance, 'djust_exclude_fields', [])
model_allowlist = getattr(model_instance, 'djust_serializable_fields', None)
data = {}
for field in model_instance._meta.concrete_fields:
name = field.name
# Skip any blacklisted or excluded fields
if name in merged_denylist or name in model_excludes:
continue
# Enforce strict allowlist if defined
if model_allowlist is not None and name not in model_allowlist:
# Always allow crucial identity fields
if name not in ['id', 'pk']:
continue
data[name] = field.value_from_object(model_instance)
return dataIn addition to the database serialization enhancements, the JIT compiler's fallback behavior was modified. When a model instance is evaluated without explicit field selection (e.g., passing a model object to a generic helper or referencing user directly), the engine no longer attempts to serialize the complete object. Instead, it emits a minimal representation containing only id, pk, __model__, and the string representation of the object (__str__). This architectural design prevents inadvertent exposure even when custom rules are omitted.
Exploitation of CVE-2026-61588 requires no specialized exploit code or exploit toolkits. Because the vulnerability is an over-serialization flaw, the server itself pushes the sensitive fields directly to the user's browser. An attacker merely needs to inspect the incoming websocket frames or static HTML state-snapshots to extract the data.
An administrative session is not required to extract the logged-in user's own credentials. A low-privileged attacker can register a normal user account and navigate to any interactive view that binds their own model instance. By opening the developer tools, filtering for active websocket traffic, and selecting the initialization frame, the attacker will find their own PBKDF2 password hash within the JSON structure. This hash can then be extracted for offline cracking attacks.
In scenarios where a view displays a list of objects—such as workspace members or directories—and binds those models to a public attribute, the attacker can harvest information for other users. This includes obtaining the is_staff or is_superuser status of accounts across the platform. This information is highly valuable for mapping out high-privilege targets, facilitating lateral movement and privilege escalation inside the target network.
The CVSS v3.1 score of 6.5 (Medium) reflects the read-only nature of the leak, but the downstream risk to confidentiality is significant. Password hashes retrieved from serialized states allow attackers to initiate high-speed offline cracking campaigns. If weak passwords are used by personnel, those accounts can be completely compromised, bypassing authentication mechanisms on other systems that share credentials.
Additionally, exposing privilege flags like is_superuser and is_staff removes the opacity of the application's access control architecture. Attackers can pinpoint administrative users with perfect accuracy. Private personal information (PII) and authentication tokens used for external APIs might also be exposed if they are stored in fields belonging to the serialized model.
While the vulnerability lacks an active exploit signature in the wild, its structural nature makes it highly predictable. Any deployment using djust version prior to 1.0.7 is implicitly affected if models are assigned to public view fields. This makes remediation urgent for enterprise instances handling personal or financial data.
The primary remediation path is upgrading the djust library to version 1.0.7 or later. This upgrade instantiates secure-by-default serialization behaviors, establishing a built-in denylist that strips passwords and staff/superuser flags automatically during recursive serialization. It also enables project-wide configuration via the DJUST_SENSITIVE_FIELDS setting in Django's configuration.
For instances where an immediate framework upgrade is impossible, developers should implement immediate tactical workarounds. The most robust immediate patch is to convert public view attributes to private view attributes. In djust, prefixing an attribute with a leading underscore (such as self._user instead of self.user) marks it as private, completely excluding it from client-side synchronization and snapshots.
Alternatively, developers can manually structure data representation by extracting only the specific primitive fields required by the user interface. Rather than assigning the complete user model, assign simple primitive strings like self.username = request.user.username and self.email = request.user.email. This prevents any automatic or fallback serialization from touching the model instance directly, maintaining a strict boundary between database objects and the network layer.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
djust djust-org | < 1.0.7 | 1.0.7 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-200, CWE-359 |
| Attack Vector | Network |
| CVSS v3.1 | 6.5 (Medium) |
| EPSS Score | Not indexed |
| Impact | High Confidentiality Exposure |
| Exploit Status | None (Theoretical) |
| KEV Status | Not listed |
The product exposes sensitive information to an actor who is not authorized to have access to that information.
A comprehensive technical analysis of six Cross-Site Scripting (XSS) vulnerability classes in the djust framework versions 1.0.0 through 1.1.0, involving escaping failures across the Python-Rust template boundary and stateful WebSocket cache lifecycles.
An escaping defect in the djust templating engine allows Cross-Site Scripting (XSS) when a template binding construct shadows a variable that was previously marked safe. The Rust-based context safety tracking incorrectly preserves name-based safety grants even after the variable name has been bound to a new, untrusted value.
A critical denial of service vulnerability exists in the HAPI FHIR SHCParser within the org.hl7.fhir.core Java library. Unbounded decompression of raw DEFLATE data during Smart Health Card parsing allows unauthenticated remote attackers to trigger JVM heap exhaustion and crash the application.
CVE-2026-81876 is a high-severity Denial of Service vulnerability in HAPI FHIR, a complete Java implementation of the HL7 FHIR standard. The vulnerability stems from improper usage of Java's java.util.zip.Inflater class within the Smart Health Card (SHC) parser.
CVE-2026-82399 is a resource management vulnerability in CoreDNS affecting custom DNS transport pathways. Prior to version 1.14.7, transports including DNS-over-HTTPS (DoH), DNS-over-QUIC (DoQ), and DNS-over-gRPC executed the resource-intensive unpack method of the underlying Go DNS library on raw, untrusted incoming payloads before validating the fixed 12-byte DNS header. An unauthenticated remote attacker can exploit this behavior by using nested DNS name compression pointers to trigger substantial heap allocations, leading to memory exhaustion and server termination.
An infinite loop vulnerability in ReactPHP's react/http chunked transfer encoding decoder (v0.6.0 up to 1.11.1) allows unauthenticated remote attackers to trigger a denial of service (DoS) by sending crafted chunked requests or responses, completely freezing the single-threaded event loop and pegging CPU usage to 100%.