Cross-site scripting (XSS) in the decidim admin panel with QuillJS WYSWYG editor
Description
decidim is a Free Open-Source participatory democracy, citizen participation and open government for cities and organizations. The WYSWYG editor QuillJS is subject to potential XSS attach in case the attacker manages to modify the HTML before being uploaded to the server. The attacker is able to change e.g. to <svg onload=alert('XSS')> if they know how to craft these requests themselves. This issue has been addressed in release version 0.27.7. All users are advised to upgrade. Users unable to upgrade should review the user accounts that have access to the admin panel (i.e. general Administrators, and participatory space's Administrators) and remove access to them if they don't need it. Disable the "Enable rich text editor for participants" setting in the admin dashboard
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
decidimRubyGems | < 0.27.7 | 0.27.7 |
Affected products
1Patches
2e5964b87fc9747adca81cabePrevents showing a malformed value in WYSIWYG editor (#12925)
2 files changed · +39 −2
decidim-admin/spec/system/admin_manages_organization_spec.rb+26 −1 modified@@ -221,7 +221,7 @@ expect(page).to have_content("Organization updated successfully") expect(find( "#organization-admin_terms_of_use_body-tabs-admin_terms_of_use_body-panel-0 .editor .ql-editor" - )["innerHTML"]).to eq("<p>bar baz</p>") + )["innerHTML"]).to eq("<p>bar baz</p><p><br></p>") end end @@ -468,6 +468,31 @@ ) end end + + context "when adding malformed content" do + let(:organization) { create(:organization, admin_terms_of_use_body: {}) } + + it "does not saves it" do + WebMock.stub_request(:get, "http://example.org/x").to_return(status: 404) + + accept_alert do + page.execute_script( + <<~JS + var element = document.querySelector("#organization-admin_terms_of_use_body-tabs-admin_terms_of_use_body-panel-0 div[contenteditable='true'].ql-editor"); + element.innerHTML = "testing <img src='http://example.org/x' onerror=alert(1) >"; + JS + ) + end + + click_button "Update" + + sleep 1 + + expect(find( + "#organization-admin_terms_of_use_body-tabs-admin_terms_of_use_body-panel-0 .editor .ql-editor" + )["innerHTML"]).to eq("<p>testing</p><p><img src=\"http://example.org/x\"></p>") + end + end end end
decidim-core/lib/decidim/form_builder.rb+13 −1 modified@@ -1,6 +1,7 @@ # frozen_string_literal: true require "foundation_rails_helper/form_builder" +require_relative "../../app/helpers/decidim/sanitize_helper" module Decidim # This custom FormBuilder adds fields needed to deal with translatable fields, @@ -9,6 +10,7 @@ class FormBuilder < FoundationRailsHelper::FormBuilder include ActionView::Context include Decidim::TranslatableAttributes include Decidim::Map::Autocomplete::FormBuilder + include Decidim::SanitizeHelper # Public: generates a check boxes input from a collection and adds help # text and errors. @@ -192,11 +194,12 @@ def editor(name, options = {}) options.delete(:required) hashtaggable = options.delete(:hashtaggable) hidden_options = extract_validations(name, options).merge(options) + sanitized_value = sanitize_editor_value(object.send(name)) content_tag(:div, class: "editor #{"hashtags__container" if hashtaggable}") do template = "" template += label(name, label_text + required_for_attribute(name)) if options.fetch(:label, true) - template += hidden_field(name, hidden_options) + template += hidden_field(name, hidden_options.merge(value: sanitized_value)) template += content_tag(:div, nil, class: "editor-container #{"js-hashtags" if hashtaggable}", data: { toolbar: toolbar, disabled: options[:disabled], @@ -941,5 +944,14 @@ def resource_class(attribute) object.class end + + # Private: Sanitize editor values to prevent malformed values being display in the + # WYSIWYG editor + # + def sanitize_editor_value(value) + sanitized_value = decidim_sanitize_editor_admin(value) + + sanitized_value == %(<div class="ql-editor-display"></div>) ? "" : sanitized_value + end end end
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-vvqw-fqwx-mqmmghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-39910ghsaADVISORY
- github.com/decidim/decidim/commit/47adca81cabea898005ec07b130b008f2a2be99fghsax_refsource_MISCWEB
- github.com/decidim/decidim/security/advisories/GHSA-vvqw-fqwx-mqmmghsax_refsource_CONFIRMWEB
- github.com/rubysec/ruby-advisory-db/blob/master/gems/decidim/CVE-2024-39910.ymlghsaWEB
News mentions
0No linked articles in our index yet.