VYPR
Moderate severityNVD Advisory· Published Sep 16, 2024· Updated Sep 16, 2024

Cross-site scripting (XSS) in the decidim admin panel with QuillJS WYSWYG editor

CVE-2024-39910

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.

PackageAffected versionsPatched versions
decidimRubyGems
< 0.27.70.27.7

Affected products

1

Patches

2
47adca81cabe

Prevents showing a malformed value in WYSIWYG editor (#12925)

https://github.com/decidim/decidimAndrés Pereira de LucenaJun 16, 2024via ghsa
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

News mentions

0

No linked articles in our index yet.