XWiki Platform: Remote code execution from account via SearchSuggestSourceSheet
Description
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.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.xwiki.platform:xwiki-platform-search-uiMaven | >= 5.2-milestone-2, < 14.10.20 | 14.10.20 |
org.xwiki.platform:xwiki-platform-search-uiMaven | >= 15.0-rc-1, < 15.5.4 | 15.5.4 |
org.xwiki.platform:xwiki-platform-search-uiMaven | >= 15.6-rc-1, < 15.10-rc-1 | 15.10-rc-1 |
Affected products
1- Range: >= 5.2-milestone-2, < 14.10.20
Patches
30317a3aa7806XWIKI-21474: Improve escaping in XWiki.SearchSuggestSourceSheet
2 files changed · +91 −1
xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-ui/src/main/resources/XWiki/SearchSuggestSourceSheet.xml+1 −1 modified@@ -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
xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-ui/src/test/java/org/xwiki/search/ui/SearchSuggestSourceSheetPageTest.java+90 −0 added@@ -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()); + } + } +}
2740974c32dbXWIKI-21474: Improve escaping in XWiki.SearchSuggestSourceSheet
2 files changed · +91 −1
xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-ui/src/main/resources/XWiki/SearchSuggestSourceSheet.xml+1 −1 modified@@ -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
xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-ui/src/test/java/org/xwiki/search/ui/SearchSuggestSourceSheetPageTest.java+90 −0 added@@ -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()); + } + } +}
6a7f19f64240XWIKI-21474: Improve escaping in XWiki.SearchSuggestSourceSheet
2 files changed · +91 −1
xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-ui/src/main/resources/XWiki/SearchSuggestSourceSheet.xml+1 −1 modified@@ -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
xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-ui/src/test/java/org/xwiki/search/ui/SearchSuggestSourceSheetPageTest.java+90 −0 added@@ -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()); + } + } +}
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
8- github.com/advisories/GHSA-34fj-r5gq-7395ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-31465ghsaADVISORY
- github.com/xwiki/xwiki-platform/commit/0317a3aa78065e66c86fc725976b06bf7f9b446eghsax_refsource_MISCWEB
- github.com/xwiki/xwiki-platform/commit/2740974c32dbb7cc565546d0f04e2374b32b36f7ghsax_refsource_MISCWEB
- github.com/xwiki/xwiki-platform/commit/6a7f19f6424036fce3d703413137adde950ae809ghsax_refsource_MISCWEB
- github.com/xwiki/xwiki-platform/commit/6a7f19f6424036fce3d703413137adde950ae809ghsax_refsource_MISCWEB
- github.com/xwiki/xwiki-platform/security/advisories/GHSA-34fj-r5gq-7395ghsax_refsource_CONFIRMWEB
- jira.xwiki.org/browse/XWIKI-21474ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.