CVE-2024-31465 (XML, published 2024-04-10T20:15Z)
Description: value: 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`.
Severity: nan (CVSS v3 base score: )
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/xwiki/xwiki-platform
Files changed:
xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-ui/src/main/resources/XWiki/SearchSuggestSourceSheet.xml
xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-ui/src/test/java/org/xwiki/search/ui/SearchSuggestSourceSheetPageTest.java
Commit message: XWIKI-21474: Improve escaping in XWiki.SearchSuggestSourceSheet


Vulnerable code:
        {{{$!object.getProperty($property.name).value}}}

Fixed code:
        $services.rendering.escape($!object.getProperty($property.name).value, 'xwiki/2.1')
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());
        }
    }
}