CVE-2024-31465 (published 2024-04-10T20:15Z)

XWiki Platform is a generic wiki platform. Starting in version 5.0-rc-1 and prior to versions 14.10.20, 15.5.4, and 15.9-rc-1, any user with edit right on any page can execute any code on the server by adding an object of type `XWiki.SearchSuggestSourceClass` to their user profile or any other page. This compromises the confidentiality, integrity and availability of the whole XWiki installation. This vulnerability has been patched in XWiki 14.10.20, 15.5.4 and 15.10 RC1. As a workaround, manually apply the patch to the document `XWiki.SearchSuggestSourceSheet`.


Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/xwiki/xwiki-platform
commit_details: repo_url: https://github.com/xwiki/xwiki-platform
author: pjeanjean
author_date: 2023-11-09 16:37:59+01:00
msg: XWIKI-21474: Improve escaping in XWiki.SearchSuggestSourceSheet
repository: repo_url: https://github.com/xwiki/xwiki-platform
repo_name: xwiki/xwiki-platform
description: The XWiki platform
repo_language: Java
owner: xwiki
file_changes: filename: SearchSuggestSourceSheet.xml
change_type: ModificationType.MODIFY
diff: @@ -70,7 +70,7 @@
     : #if ($editing)
         $doc.display($property.name, 'edit')
       #else
-        {{{$!object.getProperty($property.name).value}}}
+        $services.rendering.escape($!object.getProperty($property.name).value, 'xwiki/2.1')
       #end
   #end
 #end

programming_language: PHP
filename: SearchSuggestSourceSheetPageTest.java
change_type: ModificationType.ADD
diff: @@ -0,0 +1,90 @@
+package org.xwiki.search.ui;
+
+import org.jsoup.nodes.Document;
+import org.jsoup.select.Elements;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.xwiki.model.reference.DocumentReference;
+import org.xwiki.rendering.RenderingScriptServiceComponentList;
+import org.xwiki.rendering.internal.configuration.DefaultRenderingConfigurationComponentList;
+import org.xwiki.test.annotation.ComponentList;
+import org.xwiki.test.page.HTML50ComponentList;
+import org.xwiki.test.page.PageTest;
+import org.xwiki.test.page.TestNoScriptMacro;
+import org.xwiki.test.page.XWikiSyntax21ComponentList;
+import org.xwiki.uiextension.script.UIExtensionScriptServiceComponentList;
+
+import com.xpn.xwiki.doc.XWikiDocument;
+import com.xpn.xwiki.objects.BaseObject;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Page test for {@code XWiki.SearchSuggestSourceSheet}.
+ *
+ * @version $Id$
+ */
+@ComponentList({
+    TestNoScriptMacro.class
+})
+@UIExtensionScriptServiceComponentList
+@RenderingScriptServiceComponentList
+@DefaultRenderingConfigurationComponentList
+@HTML50ComponentList
+@XWikiSyntax21ComponentList
+class SearchSuggestSourceSheetPageTest extends PageTest
+{
+    private static final String WIKI_NAME = "xwiki";
+
+    private static final String XWIKI_SPACE = "XWiki";
+
+    private static final DocumentReference SEARCH_SUGGEST_SOURCE_SHEET =
+        new DocumentReference(WIKI_NAME, XWIKI_SPACE, "SearchSuggestSourceSheet");
+
+    private static final DocumentReference SEARCH_SUGGEST_SOURCE_CLASS =
+        new DocumentReference(WIKI_NAME, XWIKI_SPACE, "SearchSuggestSourceClass");
+
+    private XWikiDocument searchSuggestSourceSheetDocument;
+
+    @BeforeEach
+    void setUp() throws Exception
+    {
+        this.xwiki.initializeMandatoryDocuments(this.context);
+
+        this.loadPage(SEARCH_SUGGEST_SOURCE_CLASS);
+        this.searchSuggestSourceSheetDocument = this.loadPage(SEARCH_SUGGEST_SOURCE_SHEET);
+    }
+
+    @Test
+    void checkPropertiesEscaping() throws Exception
+    {
+        // Create an instance of XWiki.SearchSuggestSourceClass with properties that require escaping.
+        String[] properties = new String[]{"name", "engine", "url", "query", "resultsNumber", "icon"};
+        String unescapedProperty = "{{/html}}}}}{{noscript}}";
+        BaseObject searchSuggestSource =
+            this.searchSuggestSourceSheetDocument.newXObject(SEARCH_SUGGEST_SOURCE_CLASS, this.context);
+        for (String property : properties) {
+            searchSuggestSource.set(property, unescapedProperty, this.context);
+        }
+        this.xwiki.saveDocument(this.searchSuggestSourceSheetDocument, this.context);
+
+        this.context.setDoc(this.searchSuggestSourceSheetDocument);
+        Document document = renderHTMLPage(this.searchSuggestSourceSheetDocument);
+        Elements labels = document.getElementsByTag("label");
+        Elements values = document.getElementsByTag("dd");
+
+        // Check that the value of the property has not been evaluated for each label that we know of.
+        for (String property : properties) {
+            int iLabel = -1;
+            for (int i = 0; i < labels.size(); i++) {
+                if (labels.get(i).text().replaceAll("^.*_", "").equals(property)) {
+                    iLabel = i;
+                    break;
+                }
+            }
+            assertTrue(iLabel >= 0, "Could not find property " + property + " in rendered document.");
+            assertEquals(unescapedProperty, values.get(iLabel).text());
+        }
+    }
+}

programming_language: Java