VYPR
Critical severityNVD Advisory· Published Apr 10, 2024· Updated Sep 25, 2025

XWiki Platform: Remote code execution as guest via DatabaseSearch

CVE-2024-31982

Description

XWiki Platform is a generic wiki platform. Starting in version 2.4-milestone-1 and prior to versions 4.10.20, 15.5.4, and 15.10-rc-1, XWiki's database search allows remote code execution through the search text. This allows remote code execution for any visitor of a public wiki or user of a closed wiki as the database search is by default accessible for all users. This impacts 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.10RC1. As a workaround, one may manually apply the patch to the page Main.DatabaseSearch. Alternatively, unless database search is explicitly used by users, this page can be deleted as this is not the default search interface of XWiki.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.xwiki.platform:xwiki-platform-search-uiMaven
>= 2.4-milestone-1, < 14.10.2014.10.20
org.xwiki.platform:xwiki-platform-search-uiMaven
>= 15.0-rc-1, < 15.5.415.5.4
org.xwiki.platform:xwiki-platform-search-uiMaven
>= 15.6-rc-1, < 15.10-rc-115.10-rc-1

Affected products

1

Patches

3
95bdd6cc6298

XWIKI-21472: Directly write RSS feed content in Main.DatabaseSearch

https://github.com/xwiki/xwiki-platformpjeanjeanNov 6, 2023via ghsa
3 files changed · +124 1
  • xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-ui/pom.xml+7 0 modified
    @@ -79,5 +79,12 @@
           <type>test-jar</type>
           <scope>test</scope>
         </dependency>
    +
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-feed-api</artifactId>
    +      <version>${project.version}</version>
    +      <scope>test</scope>
    +    </dependency>
       </dependencies>
     </project>
    
  • xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-ui/src/main/resources/Main/DatabaseSearch.xml+14 1 modified
    @@ -120,8 +120,21 @@
         #set ($discard = $feed.setDescription($services.localization.render('search.rss', [$text])))
         #set ($discard = $feed.setLanguage("$xcontext.locale"))
         #set ($discard = $feed.setCopyright($xwiki.getXWikiPreference('copyright')))
    +    #set ($feedOutput = $xwiki.feed.getFeedOutput($feed, $xwiki.getXWikiPreference('feed_type', 'rss_2.0')))
    +
         #set ($discard = $response.setContentType('application/rss+xml'))
    -    {{{$xwiki.feed.getFeedOutput($feed, $xwiki.getXWikiPreference('feed_type', 'rss_2.0'))}}}
    +    #set ($characterEncoding = 'utf-8')
    +    ## Make sure the Character Encoding response header matches the character encoding used to write the response and
    +    ## compute its length.
    +    #set ($discard = $response.setCharacterEncoding($characterEncoding))
    +    ## We write the output directly to the response to avoid the execution of the Rendering Transformations.
    +    #set ($discard = $response.writer.print($feedOutput))
    +    ## The content length is measured in bytes and one character can use more than one byte.
    +    #set ($discard = $response.setContentLength($feedOutput.getBytes($characterEncoding).size()))
    +    ## Make sure the entire content is send back to the client.
    +    #set ($discard = $response.flushBuffer())
    +    ## Make sure XWiki doesn't write any more content to the response.
    +    #set ($discard = $xcontext.setFinished(true))
       #else
         {{include reference="XWiki.Results"/}}
     
    
  • xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-ui/src/test/java/org/xwiki/search/ui/DatabaseSearchPageTest.java+103 0 added
    @@ -0,0 +1,103 @@
    +/*
    + * See the NOTICE file distributed with this work for additional
    + * information regarding copyright ownership.
    + *
    + * This is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU Lesser General Public License as
    + * published by the Free Software Foundation; either version 2.1 of
    + * the License, or (at your option) any later version.
    + *
    + * This software is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * Lesser General Public License for more details.
    + *
    + * You should have received a copy of the GNU Lesser General Public
    + * License along with this software; if not, write to the Free
    + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
    + * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
    + */
    +package org.xwiki.search.ui;
    +
    +import java.io.PrintWriter;
    +import java.io.StringWriter;
    +
    +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.rendering.syntax.Syntax;
    +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 com.xpn.xwiki.doc.XWikiDocument;
    +import com.xpn.xwiki.plugin.feed.FeedPlugin;
    +import com.xpn.xwiki.web.XWikiServletResponseStub;
    +
    +import static org.junit.jupiter.api.Assertions.assertTrue;
    +
    +/**
    + * Page test for {@code Main.DatabaseSearch}.
    + *
    + * @version $Id$
    + */
    +@ComponentList({
    +    TestNoScriptMacro.class
    +})
    +@RenderingScriptServiceComponentList
    +@DefaultRenderingConfigurationComponentList
    +@HTML50ComponentList
    +@XWikiSyntax21ComponentList
    +class DatabaseSearchPageTest extends PageTest
    +{
    +    private static final String WIKI_NAME = "xwiki";
    +
    +    private static final String MAIN_SPACE = "Main";
    +
    +    private static final DocumentReference DATABASE_SEARCH_REFERENCE =
    +        new DocumentReference(WIKI_NAME, MAIN_SPACE, "DatabaseSearch");
    +
    +    @BeforeEach
    +    void setUp()
    +    {
    +        this.xwiki.initializeMandatoryDocuments(this.context);
    +
    +        this.xwiki.getPluginManager().addPlugin("feed", FeedPlugin.class.getName(), this.context);
    +    }
    +
    +    @Test
    +    void checkRSSFeedContent() throws Exception
    +    {
    +        String unescapedText = "<b>}}}{{noscript}}</b>";
    +        String escapedText = "&lt;b&gt;}}}{{noscript}}&lt;/b&gt;";
    +
    +        this.request.put("text", unescapedText);
    +        this.context.setAction("get");
    +
    +        XWikiDocument databaseSearchDocument = loadPage(DATABASE_SEARCH_REFERENCE);
    +        this.context.setDoc(databaseSearchDocument);
    +
    +        // Get directly the writer to check the RSS feed.
    +        StringWriter out = new StringWriter();
    +        PrintWriter writer = new PrintWriter(out);
    +        this.response = new XWikiServletResponseStub() {
    +            @Override
    +            public PrintWriter getWriter()
    +            {
    +                return writer;
    +            }
    +        };
    +        this.context.setResponse(this.response);
    +
    +        String rssFeed = databaseSearchDocument.displayDocument(Syntax.PLAIN_1_0, this.context);
    +        assertTrue(rssFeed.isEmpty());
    +
    +        rssFeed = out.toString();
    +        assertTrue(rssFeed.contains("<title>search.rss [" + escapedText + "]</title>"));
    +        assertTrue(rssFeed.contains("<description>search.rss [" + escapedText + "]</description>"));
    +    }
    +}
    
3c9e4bb04286

XWIKI-21472: Directly write RSS feed content in Main.DatabaseSearch

https://github.com/xwiki/xwiki-platformpjeanjeanNov 6, 2023via ghsa
3 files changed · +124 1
  • xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-ui/pom.xml+7 0 modified
    @@ -79,5 +79,12 @@
           <type>test-jar</type>
           <scope>test</scope>
         </dependency>
    +
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-feed-api</artifactId>
    +      <version>${project.version}</version>
    +      <scope>test</scope>
    +    </dependency>
       </dependencies>
     </project>
    
  • xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-ui/src/main/resources/Main/DatabaseSearch.xml+14 1 modified
    @@ -120,8 +120,21 @@
         #set ($discard = $feed.setDescription($services.localization.render('search.rss', [$text])))
         #set ($discard = $feed.setLanguage("$xcontext.locale"))
         #set ($discard = $feed.setCopyright($xwiki.getXWikiPreference('copyright')))
    +    #set ($feedOutput = $xwiki.feed.getFeedOutput($feed, $xwiki.getXWikiPreference('feed_type', 'rss_2.0')))
    +
         #set ($discard = $response.setContentType('application/rss+xml'))
    -    {{{$xwiki.feed.getFeedOutput($feed, $xwiki.getXWikiPreference('feed_type', 'rss_2.0'))}}}
    +    #set ($characterEncoding = 'utf-8')
    +    ## Make sure the Character Encoding response header matches the character encoding used to write the response and
    +    ## compute its length.
    +    #set ($discard = $response.setCharacterEncoding($characterEncoding))
    +    ## We write the output directly to the response to avoid the execution of the Rendering Transformations.
    +    #set ($discard = $response.writer.print($feedOutput))
    +    ## The content length is measured in bytes and one character can use more than one byte.
    +    #set ($discard = $response.setContentLength($feedOutput.getBytes($characterEncoding).size()))
    +    ## Make sure the entire content is send back to the client.
    +    #set ($discard = $response.flushBuffer())
    +    ## Make sure XWiki doesn't write any more content to the response.
    +    #set ($discard = $xcontext.setFinished(true))
       #else
         {{include reference="XWiki.Results"/}}
     
    
  • xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-ui/src/test/java/org/xwiki/search/ui/DatabaseSearchPageTest.java+103 0 added
    @@ -0,0 +1,103 @@
    +/*
    + * See the NOTICE file distributed with this work for additional
    + * information regarding copyright ownership.
    + *
    + * This is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU Lesser General Public License as
    + * published by the Free Software Foundation; either version 2.1 of
    + * the License, or (at your option) any later version.
    + *
    + * This software is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * Lesser General Public License for more details.
    + *
    + * You should have received a copy of the GNU Lesser General Public
    + * License along with this software; if not, write to the Free
    + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
    + * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
    + */
    +package org.xwiki.search.ui;
    +
    +import java.io.PrintWriter;
    +import java.io.StringWriter;
    +
    +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.rendering.syntax.Syntax;
    +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 com.xpn.xwiki.doc.XWikiDocument;
    +import com.xpn.xwiki.plugin.feed.FeedPlugin;
    +import com.xpn.xwiki.web.XWikiServletResponseStub;
    +
    +import static org.junit.jupiter.api.Assertions.assertTrue;
    +
    +/**
    + * Page test for {@code Main.DatabaseSearch}.
    + *
    + * @version $Id$
    + */
    +@ComponentList({
    +    TestNoScriptMacro.class
    +})
    +@RenderingScriptServiceComponentList
    +@DefaultRenderingConfigurationComponentList
    +@HTML50ComponentList
    +@XWikiSyntax21ComponentList
    +class DatabaseSearchPageTest extends PageTest
    +{
    +    private static final String WIKI_NAME = "xwiki";
    +
    +    private static final String MAIN_SPACE = "Main";
    +
    +    private static final DocumentReference DATABASE_SEARCH_REFERENCE =
    +        new DocumentReference(WIKI_NAME, MAIN_SPACE, "DatabaseSearch");
    +
    +    @BeforeEach
    +    void setUp()
    +    {
    +        this.xwiki.initializeMandatoryDocuments(this.context);
    +
    +        this.xwiki.getPluginManager().addPlugin("feed", FeedPlugin.class.getName(), this.context);
    +    }
    +
    +    @Test
    +    void checkRSSFeedContent() throws Exception
    +    {
    +        String unescapedText = "<b>}}}{{noscript}}</b>";
    +        String escapedText = "&lt;b&gt;}}}{{noscript}}&lt;/b&gt;";
    +
    +        this.request.put("text", unescapedText);
    +        this.context.setAction("get");
    +
    +        XWikiDocument databaseSearchDocument = loadPage(DATABASE_SEARCH_REFERENCE);
    +        this.context.setDoc(databaseSearchDocument);
    +
    +        // Get directly the writer to check the RSS feed.
    +        StringWriter out = new StringWriter();
    +        PrintWriter writer = new PrintWriter(out);
    +        this.response = new XWikiServletResponseStub() {
    +            @Override
    +            public PrintWriter getWriter()
    +            {
    +                return writer;
    +            }
    +        };
    +        this.context.setResponse(this.response);
    +
    +        String rssFeed = databaseSearchDocument.displayDocument(Syntax.PLAIN_1_0, this.context);
    +        assertTrue(rssFeed.isEmpty());
    +
    +        rssFeed = out.toString();
    +        assertTrue(rssFeed.contains("<title>search.rss [" + escapedText + "]</title>"));
    +        assertTrue(rssFeed.contains("<description>search.rss [" + escapedText + "]</description>"));
    +    }
    +}
    
459e968be874

XWIKI-21472: Directly write RSS feed content in Main.DatabaseSearch

https://github.com/xwiki/xwiki-platformpjeanjeanNov 6, 2023via ghsa
3 files changed · +124 1
  • xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-ui/pom.xml+7 0 modified
    @@ -79,5 +79,12 @@
           <type>test-jar</type>
           <scope>test</scope>
         </dependency>
    +
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-feed-api</artifactId>
    +      <version>${project.version}</version>
    +      <scope>test</scope>
    +    </dependency>
       </dependencies>
     </project>
    
  • xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-ui/src/main/resources/Main/DatabaseSearch.xml+14 1 modified
    @@ -120,8 +120,21 @@
         #set ($discard = $feed.setDescription($services.localization.render('search.rss', [$text])))
         #set ($discard = $feed.setLanguage("$xcontext.locale"))
         #set ($discard = $feed.setCopyright($xwiki.getXWikiPreference('copyright')))
    +    #set ($feedOutput = $xwiki.feed.getFeedOutput($feed, $xwiki.getXWikiPreference('feed_type', 'rss_2.0')))
    +
         #set ($discard = $response.setContentType('application/rss+xml'))
    -    {{{$xwiki.feed.getFeedOutput($feed, $xwiki.getXWikiPreference('feed_type', 'rss_2.0'))}}}
    +    #set ($characterEncoding = 'utf-8')
    +    ## Make sure the Character Encoding response header matches the character encoding used to write the response and
    +    ## compute its length.
    +    #set ($discard = $response.setCharacterEncoding($characterEncoding))
    +    ## We write the output directly to the response to avoid the execution of the Rendering Transformations.
    +    #set ($discard = $response.writer.print($feedOutput))
    +    ## The content length is measured in bytes and one character can use more than one byte.
    +    #set ($discard = $response.setContentLength($feedOutput.getBytes($characterEncoding).size()))
    +    ## Make sure the entire content is send back to the client.
    +    #set ($discard = $response.flushBuffer())
    +    ## Make sure XWiki doesn't write any more content to the response.
    +    #set ($discard = $xcontext.setFinished(true))
       #else
         {{include reference="XWiki.Results"/}}
     
    
  • xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-ui/src/test/java/org/xwiki/search/ui/DatabaseSearchPageTest.java+103 0 added
    @@ -0,0 +1,103 @@
    +/*
    + * See the NOTICE file distributed with this work for additional
    + * information regarding copyright ownership.
    + *
    + * This is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU Lesser General Public License as
    + * published by the Free Software Foundation; either version 2.1 of
    + * the License, or (at your option) any later version.
    + *
    + * This software is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * Lesser General Public License for more details.
    + *
    + * You should have received a copy of the GNU Lesser General Public
    + * License along with this software; if not, write to the Free
    + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
    + * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
    + */
    +package org.xwiki.search.ui;
    +
    +import java.io.PrintWriter;
    +import java.io.StringWriter;
    +
    +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.rendering.syntax.Syntax;
    +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 com.xpn.xwiki.doc.XWikiDocument;
    +import com.xpn.xwiki.plugin.feed.FeedPlugin;
    +import com.xpn.xwiki.web.XWikiServletResponseStub;
    +
    +import static org.junit.jupiter.api.Assertions.assertTrue;
    +
    +/**
    + * Page test for {@code Main.DatabaseSearch}.
    + *
    + * @version $Id$
    + */
    +@ComponentList({
    +    TestNoScriptMacro.class
    +})
    +@RenderingScriptServiceComponentList
    +@DefaultRenderingConfigurationComponentList
    +@HTML50ComponentList
    +@XWikiSyntax21ComponentList
    +class DatabaseSearchPageTest extends PageTest
    +{
    +    private static final String WIKI_NAME = "xwiki";
    +
    +    private static final String MAIN_SPACE = "Main";
    +
    +    private static final DocumentReference DATABASE_SEARCH_REFERENCE =
    +        new DocumentReference(WIKI_NAME, MAIN_SPACE, "DatabaseSearch");
    +
    +    @BeforeEach
    +    void setUp()
    +    {
    +        this.xwiki.initializeMandatoryDocuments(this.context);
    +
    +        this.xwiki.getPluginManager().addPlugin("feed", FeedPlugin.class.getName(), this.context);
    +    }
    +
    +    @Test
    +    void checkRSSFeedContent() throws Exception
    +    {
    +        String unescapedText = "<b>}}}{{noscript}}</b>";
    +        String escapedText = "&lt;b&gt;}}}{{noscript}}&lt;/b&gt;";
    +
    +        this.request.put("text", unescapedText);
    +        this.context.setAction("get");
    +
    +        XWikiDocument databaseSearchDocument = loadPage(DATABASE_SEARCH_REFERENCE);
    +        this.context.setDoc(databaseSearchDocument);
    +
    +        // Get directly the writer to check the RSS feed.
    +        StringWriter out = new StringWriter();
    +        PrintWriter writer = new PrintWriter(out);
    +        this.response = new XWikiServletResponseStub() {
    +            @Override
    +            public PrintWriter getWriter()
    +            {
    +                return writer;
    +            }
    +        };
    +        this.context.setResponse(this.response);
    +
    +        String rssFeed = databaseSearchDocument.displayDocument(Syntax.PLAIN_1_0, this.context);
    +        assertTrue(rssFeed.isEmpty());
    +
    +        rssFeed = out.toString();
    +        assertTrue(rssFeed.contains("<title>search.rss [" + escapedText + "]</title>"));
    +        assertTrue(rssFeed.contains("<description>search.rss [" + escapedText + "]</description>"));
    +    }
    +}
    

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

10

News mentions

0

No linked articles in our index yet.