VYPR
Critical severityNVD Advisory· Published Apr 10, 2024· Updated Feb 21, 2025

XWiki Platform CSRF remote code execution through the realtime HTML Converter API

CVE-2024-31988

Description

XWiki Platform is a generic wiki platform. Starting in version 13.9-rc-1 and prior to versions 4.10.19, 15.5.4, and 15.10-rc-1, when the realtime editor is installed in XWiki, it allows arbitrary remote code execution with the interaction of an admin user with programming right. More precisely, by getting an admin user to either visit a crafted URL or to view an image with this URL that could be in a comment, the attacker can get the admin to execute arbitrary XWiki syntax including scripting macros with Groovy or Python code. This compromises the confidentiality, integrity and availability of the whole XWiki installation. This vulnerability has been patched in XWiki 14.10.19, 15.5.4 and 15.9. As a workaround, one may update RTFrontend.ConvertHTML manually with the patch. This will, however, break some synchronization processes in the realtime editor, so upgrading should be the preferred way on installations where this editor is used.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.xwiki.platform:xwiki-platform-realtime-uiMaven
>= 13.9-rc-1, < 14.10.1914.10.19
org.xwiki.platform:xwiki-platform-realtime-uiMaven
>= 15.0-rc-1, < 15.5.415.5.4
org.xwiki.platform:xwiki-platform-realtime-uiMaven
>= 15.6-rc-1, < 15.915.9

Affected products

1

Patches

4
9f8cc8849741

XWIKI-21424: Use CSRF token in the realtime HTML Converter API

https://github.com/xwiki/xwiki-platformpjeanjeanOct 10, 2023via ghsa
5 files changed · +230 4
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-ui/pom.xml+22 0 modified
    @@ -75,5 +75,27 @@
           <version>${project.version}</version>
           <scope>runtime</scope>
         </dependency>
    +    <!-- Test dependencies. -->
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-test-page</artifactId>
    +      <version>${project.version}</version>
    +      <scope>test</scope>
    +    </dependency>
    +    <!-- Provides the component list for RenderingScriptService. -->
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-rendering-xwiki</artifactId>
    +      <version>${project.version}</version>
    +      <type>test-jar</type>
    +      <scope>test</scope>
    +    </dependency>
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-rendering-configuration-default</artifactId>
    +      <version>${project.version}</version>
    +      <type>test-jar</type>
    +      <scope>test</scope>
    +    </dependency>
       </dependencies>
     </project>
    
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-ui/src/main/resources/RTFrontend/ConvertHTML.xml+8 3 modified
    @@ -20,7 +20,7 @@
      * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
     -->
     
    -<xwikidoc version="1.4" reference="RTFrontend.ConvertHTML" locale="">
    +<xwikidoc version="1.5" reference="RTFrontend.ConvertHTML" locale="">
       <web>RTFrontend</web>
       <name>ConvertHTML</name>
       <language/>
    @@ -52,8 +52,13 @@
       'documentReference': $documentReference
     })
     #if ($xcontext.action == 'get')
    -  ## FIXME: We shouldn't depend on CKEditor. This code should work independent of the configured WYSIWYG editor.
    -  $xwiki.getDocument('CKEditor.ContentSheet').getRenderedContent()
    +  ## Check that the CSRF token matches the user.
    +  #if (!$services.csrf.isTokenValid($request.form_token))
    +    $response.sendError(403, $services.localization.render('rtfFrontend.convertHtml.invalidCsrfToken'))
    +  #else
    +    ## FIXME: We shouldn't depend on CKEditor. This code should work independent of the configured WYSIWYG editor.
    +    $xwiki.getDocument('CKEditor.ContentSheet').getRenderedContent()
    +  #end
     #end
     {{/velocity}}</content>
     </xwikidoc>
    
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-ui/src/main/resources/XWiki/Realtime/Translations.xml+77 0 added
    @@ -0,0 +1,77 @@
    +<?xml version="1.1" encoding="UTF-8"?>
    +
    +<!--
    + * 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.
    +-->
    +
    +<xwikidoc version="1.5" reference="XWiki.Realtime.Translations" locale="">
    +  <web>XWiki.Realtime</web>
    +  <name>Translations</name>
    +  <language/>
    +  <defaultLanguage>en</defaultLanguage>
    +  <translation>0</translation>
    +  <creator>xwiki:XWiki.Admin</creator>
    +  <parent>Main.WebHome</parent>
    +  <author>xwiki:XWiki.Admin</author>
    +  <contentAuthor>xwiki:XWiki.Admin</contentAuthor>
    +  <version>1.1</version>
    +  <title/>
    +  <comment/>
    +  <minorEdit>false</minorEdit>
    +  <syntaxId>plain/1.0</syntaxId>
    +  <hidden>true</hidden>
    +  <content>rtfFrontend.convertHtml.invalidCsrfToken=Invalid CSRF Token</content>
    +  <object>
    +    <name>XWiki.Realtime.Translations</name>
    +    <number>0</number>
    +    <className>XWiki.TranslationDocumentClass</className>
    +    <guid>41105c55-62ec-47bc-9dd0-c502cad68de6</guid>
    +    <class>
    +      <name>XWiki.TranslationDocumentClass</name>
    +      <customClass/>
    +      <customMapping/>
    +      <defaultViewSheet/>
    +      <defaultEditSheet/>
    +      <defaultWeb/>
    +      <nameField/>
    +      <validationScript/>
    +      <scope>
    +        <cache>0</cache>
    +        <disabled>0</disabled>
    +        <displayType>select</displayType>
    +        <freeText>forbidden</freeText>
    +        <largeStorage>0</largeStorage>
    +        <multiSelect>0</multiSelect>
    +        <name>scope</name>
    +        <number>1</number>
    +        <prettyName>Scope</prettyName>
    +        <relationalStorage>0</relationalStorage>
    +        <separator> </separator>
    +        <separators>|, </separators>
    +        <size>1</size>
    +        <unmodifiable>0</unmodifiable>
    +        <values>GLOBAL|WIKI|USER|ON_DEMAND</values>
    +        <classType>com.xpn.xwiki.objects.classes.StaticListClass</classType>
    +      </scope>
    +    </class>
    +    <property>
    +      <scope>WIKI</scope>
    +    </property>
    +  </object>
    +</xwikidoc>
    
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-ui/src/test/java/org/xwiki/realtime/ui/ConvertHTMLPageTest.java+118 0 added
    @@ -0,0 +1,118 @@
    +/*
    + * 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.realtime.ui;
    +
    +import javax.inject.Provider;
    +
    +import org.jsoup.nodes.Document;
    +import org.junit.jupiter.api.BeforeEach;
    +import org.junit.jupiter.api.Test;
    +import org.xwiki.csrf.script.CSRFTokenScriptService;
    +import org.xwiki.model.reference.DocumentReference;
    +import org.xwiki.rendering.RenderingScriptServiceComponentList;
    +import org.xwiki.rendering.internal.configuration.DefaultRenderingConfigurationComponentList;
    +import org.xwiki.script.service.ScriptService;
    +import org.xwiki.test.page.HTML50ComponentList;
    +import org.xwiki.test.page.PageTest;
    +import org.xwiki.test.page.XWikiSyntax21ComponentList;
    +
    +import com.xpn.xwiki.XWikiContext;
    +import com.xpn.xwiki.user.api.XWikiRightService;
    +
    +import static org.junit.jupiter.api.Assertions.assertEquals;
    +import static org.mockito.ArgumentMatchers.anyInt;
    +import static org.mockito.Mockito.mock;
    +import static org.mockito.Mockito.never;
    +import static org.mockito.Mockito.spy;
    +import static org.mockito.Mockito.verify;
    +import static org.mockito.Mockito.when;
    +
    +@RenderingScriptServiceComponentList
    +@DefaultRenderingConfigurationComponentList
    +@HTML50ComponentList
    +@XWikiSyntax21ComponentList
    +class ConvertHTMLPageTest extends PageTest
    +{
    +
    +    private static final String WIKI_NAME = "xwiki";
    +
    +    private static final String XWIKI_SPACE = "RTFrontend";
    +
    +    private static final DocumentReference RTF_FRONTEND_CONVERT_HTML =
    +        new DocumentReference(WIKI_NAME, XWIKI_SPACE, "ConvertHTML");
    +
    +    private static final String CSRF_TOKEN = "a0a0a0a0";
    +
    +    private CSRFTokenScriptService tokenService;
    +
    +    @BeforeEach
    +    void setUp() throws Exception
    +    {
    +        // Mock the Token Service to get a consistent CSRF token throughout the tests.
    +        this.tokenService = this.oldcore.getMocker().registerMockComponent(ScriptService.class, "csrf",
    +            CSRFTokenScriptService.class, true);
    +        when(this.tokenService.isTokenValid(CSRF_TOKEN)).thenReturn(true);
    +
    +        this.xwiki.initializeMandatoryDocuments(this.context);
    +
    +        this.context = mock(XWikiContext.class);
    +        Provider<XWikiContext> xcontextProvider =
    +            this.componentManager.registerMockComponent(XWikiContext.TYPE_PROVIDER);
    +        when(xcontextProvider.get()).thenReturn(this.context);
    +        when(this.context.getRequest()).thenReturn(this.request);
    +        when(this.context.getResponse()).thenReturn(this.response);
    +        when(this.context.getWiki()).thenReturn(this.xwiki);
    +
    +        // Fake programming access level to display the complete page.
    +        XWikiRightService rightService = this.oldcore.getMockRightService();
    +        when(this.xwiki.getRightService()).thenReturn(rightService);
    +        when(rightService.hasProgrammingRights(this.context)).thenReturn(true);
    +        this.response = spy(this.response);
    +        when(this.context.getResponse()).thenReturn(this.response);
    +    }
    +
    +    @Test
    +    void checkValidCSRFToken() throws Exception
    +    {
    +        when(this.context.getAction()).thenReturn("get");
    +        this.request.put("text", "Hello");
    +        this.request.put("form_token", CSRF_TOKEN);
    +        Document result = renderHTMLPage(RTF_FRONTEND_CONVERT_HTML);
    +
    +        verify(this.response, never()).setStatus(anyInt());
    +        verify(this.tokenService).isTokenValid(CSRF_TOKEN);
    +        assertEquals("$xwiki.getDocument('CKEditor.ContentSheet').getRenderedContent()",
    +            result.getElementsByTag("body").text());
    +    }
    +
    +    @Test
    +    void checkInvalidCSRFToken() throws Exception
    +    {
    +        String wrongToken = "wrong_token";
    +        when(this.context.getAction()).thenReturn("get");
    +        this.request.put("text", "Hello");
    +        this.request.put("form_token", wrongToken);
    +        Document result = renderHTMLPage(RTF_FRONTEND_CONVERT_HTML);
    +
    +        verify(this.response).sendError(403, "rtfFrontend.convertHtml.invalidCsrfToken");
    +        verify(this.tokenService).isTokenValid(wrongToken);
    +        assertEquals("", result.getElementsByTag("body").text());
    +    }
    +}
    
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-webjar/src/main/webjar/loader.js+5 1 modified
    @@ -71,7 +71,11 @@ define('xwiki-realtime-loader', [
         var userReference = xm.userReference ? XWiki.Model.serialize(xm.userReference) : 'xwiki:XWiki.XWikiGuest';
         return {
           WebsocketURL: realtimeConfig.webSocketURL,
    -      htmlConverterUrl: new XWiki.Document('ConvertHTML', 'RTFrontend').getURL('get', 'xpage=plain&outputSyntax=plain'),
    +      htmlConverterUrl: new XWiki.Document('ConvertHTML', 'RTFrontend').getURL('get', $.param({
    +        'xpage': 'plain',
    +        'outputSyntax': 'plain',
    +        'form_token': document.documentElement.dataset.xwikiFormToken
    +      })),
           // userId === <userReference>-encoded(<userName>)%2d<randomNumber>
           userName: userReference + '-' + encodeURIComponent(realtimeConfig.user.name + '-').replace(/-/g, '%2d') +
             String(Math.random()).substring(2),
    
d9f5043da289

XWIKI-21424: Use CSRF token in the realtime HTML Converter API

https://github.com/xwiki/xwiki-platformpjeanjeanOct 10, 2023via ghsa
5 files changed · +230 4
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-ui/pom.xml+22 0 modified
    @@ -75,5 +75,27 @@
           <version>${project.version}</version>
           <scope>runtime</scope>
         </dependency>
    +    <!-- Test dependencies. -->
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-test-page</artifactId>
    +      <version>${project.version}</version>
    +      <scope>test</scope>
    +    </dependency>
    +    <!-- Provides the component list for RenderingScriptService. -->
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-rendering-xwiki</artifactId>
    +      <version>${project.version}</version>
    +      <type>test-jar</type>
    +      <scope>test</scope>
    +    </dependency>
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-rendering-configuration-default</artifactId>
    +      <version>${project.version}</version>
    +      <type>test-jar</type>
    +      <scope>test</scope>
    +    </dependency>
       </dependencies>
     </project>
    
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-ui/src/main/resources/RTFrontend/ConvertHTML.xml+8 3 modified
    @@ -20,7 +20,7 @@
      * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
     -->
     
    -<xwikidoc version="1.4" reference="RTFrontend.ConvertHTML" locale="">
    +<xwikidoc version="1.5" reference="RTFrontend.ConvertHTML" locale="">
       <web>RTFrontend</web>
       <name>ConvertHTML</name>
       <language/>
    @@ -52,8 +52,13 @@
       'documentReference': $documentReference
     })
     #if ($xcontext.action == 'get')
    -  ## FIXME: We shouldn't depend on CKEditor. This code should work independent of the configured WYSIWYG editor.
    -  $xwiki.getDocument('CKEditor.ContentSheet').getRenderedContent()
    +  ## Check that the CSRF token matches the user.
    +  #if (!$services.csrf.isTokenValid($request.form_token))
    +    $response.sendError(403, $services.localization.render('rtfFrontend.convertHtml.invalidCsrfToken'))
    +  #else
    +    ## FIXME: We shouldn't depend on CKEditor. This code should work independent of the configured WYSIWYG editor.
    +    $xwiki.getDocument('CKEditor.ContentSheet').getRenderedContent()
    +  #end
     #end
     {{/velocity}}</content>
     </xwikidoc>
    
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-ui/src/main/resources/XWiki/Realtime/Translations.xml+77 0 added
    @@ -0,0 +1,77 @@
    +<?xml version="1.1" encoding="UTF-8"?>
    +
    +<!--
    + * 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.
    +-->
    +
    +<xwikidoc version="1.5" reference="XWiki.Realtime.Translations" locale="">
    +  <web>XWiki.Realtime</web>
    +  <name>Translations</name>
    +  <language/>
    +  <defaultLanguage>en</defaultLanguage>
    +  <translation>0</translation>
    +  <creator>xwiki:XWiki.Admin</creator>
    +  <parent>Main.WebHome</parent>
    +  <author>xwiki:XWiki.Admin</author>
    +  <contentAuthor>xwiki:XWiki.Admin</contentAuthor>
    +  <version>1.1</version>
    +  <title/>
    +  <comment/>
    +  <minorEdit>false</minorEdit>
    +  <syntaxId>plain/1.0</syntaxId>
    +  <hidden>true</hidden>
    +  <content>rtfFrontend.convertHtml.invalidCsrfToken=Invalid CSRF Token</content>
    +  <object>
    +    <name>XWiki.Realtime.Translations</name>
    +    <number>0</number>
    +    <className>XWiki.TranslationDocumentClass</className>
    +    <guid>41105c55-62ec-47bc-9dd0-c502cad68de6</guid>
    +    <class>
    +      <name>XWiki.TranslationDocumentClass</name>
    +      <customClass/>
    +      <customMapping/>
    +      <defaultViewSheet/>
    +      <defaultEditSheet/>
    +      <defaultWeb/>
    +      <nameField/>
    +      <validationScript/>
    +      <scope>
    +        <cache>0</cache>
    +        <disabled>0</disabled>
    +        <displayType>select</displayType>
    +        <freeText>forbidden</freeText>
    +        <largeStorage>0</largeStorage>
    +        <multiSelect>0</multiSelect>
    +        <name>scope</name>
    +        <number>1</number>
    +        <prettyName>Scope</prettyName>
    +        <relationalStorage>0</relationalStorage>
    +        <separator> </separator>
    +        <separators>|, </separators>
    +        <size>1</size>
    +        <unmodifiable>0</unmodifiable>
    +        <values>GLOBAL|WIKI|USER|ON_DEMAND</values>
    +        <classType>com.xpn.xwiki.objects.classes.StaticListClass</classType>
    +      </scope>
    +    </class>
    +    <property>
    +      <scope>WIKI</scope>
    +    </property>
    +  </object>
    +</xwikidoc>
    
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-ui/src/test/java/org/xwiki/realtime/ui/ConvertHTMLPageTest.java+118 0 added
    @@ -0,0 +1,118 @@
    +/*
    + * 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.realtime.ui;
    +
    +import javax.inject.Provider;
    +
    +import org.jsoup.nodes.Document;
    +import org.junit.jupiter.api.BeforeEach;
    +import org.junit.jupiter.api.Test;
    +import org.xwiki.csrf.script.CSRFTokenScriptService;
    +import org.xwiki.model.reference.DocumentReference;
    +import org.xwiki.rendering.RenderingScriptServiceComponentList;
    +import org.xwiki.rendering.internal.configuration.DefaultRenderingConfigurationComponentList;
    +import org.xwiki.script.service.ScriptService;
    +import org.xwiki.test.page.HTML50ComponentList;
    +import org.xwiki.test.page.PageTest;
    +import org.xwiki.test.page.XWikiSyntax21ComponentList;
    +
    +import com.xpn.xwiki.XWikiContext;
    +import com.xpn.xwiki.user.api.XWikiRightService;
    +
    +import static org.junit.jupiter.api.Assertions.assertEquals;
    +import static org.mockito.ArgumentMatchers.anyInt;
    +import static org.mockito.Mockito.mock;
    +import static org.mockito.Mockito.never;
    +import static org.mockito.Mockito.spy;
    +import static org.mockito.Mockito.verify;
    +import static org.mockito.Mockito.when;
    +
    +@RenderingScriptServiceComponentList
    +@DefaultRenderingConfigurationComponentList
    +@HTML50ComponentList
    +@XWikiSyntax21ComponentList
    +class ConvertHTMLPageTest extends PageTest
    +{
    +
    +    private static final String WIKI_NAME = "xwiki";
    +
    +    private static final String XWIKI_SPACE = "RTFrontend";
    +
    +    private static final DocumentReference RTF_FRONTEND_CONVERT_HTML =
    +        new DocumentReference(WIKI_NAME, XWIKI_SPACE, "ConvertHTML");
    +
    +    private static final String CSRF_TOKEN = "a0a0a0a0";
    +
    +    private CSRFTokenScriptService tokenService;
    +
    +    @BeforeEach
    +    void setUp() throws Exception
    +    {
    +        // Mock the Token Service to get a consistent CSRF token throughout the tests.
    +        this.tokenService = this.oldcore.getMocker().registerMockComponent(ScriptService.class, "csrf",
    +            CSRFTokenScriptService.class, true);
    +        when(this.tokenService.isTokenValid(CSRF_TOKEN)).thenReturn(true);
    +
    +        this.xwiki.initializeMandatoryDocuments(this.context);
    +
    +        this.context = mock(XWikiContext.class);
    +        Provider<XWikiContext> xcontextProvider =
    +            this.componentManager.registerMockComponent(XWikiContext.TYPE_PROVIDER);
    +        when(xcontextProvider.get()).thenReturn(this.context);
    +        when(this.context.getRequest()).thenReturn(this.request);
    +        when(this.context.getResponse()).thenReturn(this.response);
    +        when(this.context.getWiki()).thenReturn(this.xwiki);
    +
    +        // Fake programming access level to display the complete page.
    +        XWikiRightService rightService = this.oldcore.getMockRightService();
    +        when(this.xwiki.getRightService()).thenReturn(rightService);
    +        when(rightService.hasProgrammingRights(this.context)).thenReturn(true);
    +        this.response = spy(this.response);
    +        when(this.context.getResponse()).thenReturn(this.response);
    +    }
    +
    +    @Test
    +    void checkValidCSRFToken() throws Exception
    +    {
    +        when(this.context.getAction()).thenReturn("get");
    +        this.request.put("text", "Hello");
    +        this.request.put("form_token", CSRF_TOKEN);
    +        Document result = renderHTMLPage(RTF_FRONTEND_CONVERT_HTML);
    +
    +        verify(this.response, never()).setStatus(anyInt());
    +        verify(this.tokenService).isTokenValid(CSRF_TOKEN);
    +        assertEquals("$xwiki.getDocument('CKEditor.ContentSheet').getRenderedContent()",
    +            result.getElementsByTag("body").text());
    +    }
    +
    +    @Test
    +    void checkInvalidCSRFToken() throws Exception
    +    {
    +        String wrongToken = "wrong_token";
    +        when(this.context.getAction()).thenReturn("get");
    +        this.request.put("text", "Hello");
    +        this.request.put("form_token", wrongToken);
    +        Document result = renderHTMLPage(RTF_FRONTEND_CONVERT_HTML);
    +
    +        verify(this.response).sendError(403, "rtfFrontend.convertHtml.invalidCsrfToken");
    +        verify(this.tokenService).isTokenValid(wrongToken);
    +        assertEquals("", result.getElementsByTag("body").text());
    +    }
    +}
    
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-webjar/src/main/webjar/loader.js+5 1 modified
    @@ -71,7 +71,11 @@ define('xwiki-realtime-loader', [
         var userReference = xm.userReference ? XWiki.Model.serialize(xm.userReference) : 'xwiki:XWiki.XWikiGuest';
         return {
           WebsocketURL: realtimeConfig.webSocketURL,
    -      htmlConverterUrl: new XWiki.Document('ConvertHTML', 'RTFrontend').getURL('get', 'xpage=plain&outputSyntax=plain'),
    +      htmlConverterUrl: new XWiki.Document('ConvertHTML', 'RTFrontend').getURL('get', $.param({
    +        'xpage': 'plain',
    +        'outputSyntax': 'plain',
    +        'form_token': document.documentElement.dataset.xwikiFormToken
    +      })),
           // userId === <userReference>-encoded(<userName>)%2d<randomNumber>
           userName: userReference + '-' + encodeURIComponent(realtimeConfig.user.name + '-').replace(/-/g, '%2d') +
             String(Math.random()).substring(2),
    
4896712ee648

XWIKI-21424: Use CSRF token in the realtime HTML Converter API

https://github.com/xwiki/xwiki-platformpjeanjeanOct 10, 2023via ghsa
5 files changed · +230 4
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-ui/pom.xml+22 0 modified
    @@ -75,5 +75,27 @@
           <version>${project.version}</version>
           <scope>runtime</scope>
         </dependency>
    +    <!-- Test dependencies. -->
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-test-page</artifactId>
    +      <version>${project.version}</version>
    +      <scope>test</scope>
    +    </dependency>
    +    <!-- Provides the component list for RenderingScriptService. -->
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-rendering-xwiki</artifactId>
    +      <version>${project.version}</version>
    +      <type>test-jar</type>
    +      <scope>test</scope>
    +    </dependency>
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-rendering-configuration-default</artifactId>
    +      <version>${project.version}</version>
    +      <type>test-jar</type>
    +      <scope>test</scope>
    +    </dependency>
       </dependencies>
     </project>
    
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-ui/src/main/resources/RTFrontend/ConvertHTML.xml+8 3 modified
    @@ -20,7 +20,7 @@
      * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
     -->
     
    -<xwikidoc version="1.4" reference="RTFrontend.ConvertHTML" locale="">
    +<xwikidoc version="1.5" reference="RTFrontend.ConvertHTML" locale="">
       <web>RTFrontend</web>
       <name>ConvertHTML</name>
       <language/>
    @@ -52,8 +52,13 @@
       'documentReference': $documentReference
     })
     #if ($xcontext.action == 'get')
    -  ## FIXME: We shouldn't depend on CKEditor. This code should work independent of the configured WYSIWYG editor.
    -  $xwiki.getDocument('CKEditor.ContentSheet').getRenderedContent()
    +  ## Check that the CSRF token matches the user.
    +  #if (!$services.csrf.isTokenValid($request.form_token))
    +    $response.sendError(403, $services.localization.render('rtfFrontend.convertHtml.invalidCsrfToken'))
    +  #else
    +    ## FIXME: We shouldn't depend on CKEditor. This code should work independent of the configured WYSIWYG editor.
    +    $xwiki.getDocument('CKEditor.ContentSheet').getRenderedContent()
    +  #end
     #end
     {{/velocity}}</content>
     </xwikidoc>
    
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-ui/src/main/resources/XWiki/Realtime/Translations.xml+77 0 added
    @@ -0,0 +1,77 @@
    +<?xml version="1.1" encoding="UTF-8"?>
    +
    +<!--
    + * 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.
    +-->
    +
    +<xwikidoc version="1.5" reference="XWiki.Realtime.Translations" locale="">
    +  <web>XWiki.Realtime</web>
    +  <name>Translations</name>
    +  <language/>
    +  <defaultLanguage>en</defaultLanguage>
    +  <translation>0</translation>
    +  <creator>xwiki:XWiki.Admin</creator>
    +  <parent>Main.WebHome</parent>
    +  <author>xwiki:XWiki.Admin</author>
    +  <contentAuthor>xwiki:XWiki.Admin</contentAuthor>
    +  <version>1.1</version>
    +  <title/>
    +  <comment/>
    +  <minorEdit>false</minorEdit>
    +  <syntaxId>plain/1.0</syntaxId>
    +  <hidden>true</hidden>
    +  <content>rtfFrontend.convertHtml.invalidCsrfToken=Invalid CSRF Token</content>
    +  <object>
    +    <name>XWiki.Realtime.Translations</name>
    +    <number>0</number>
    +    <className>XWiki.TranslationDocumentClass</className>
    +    <guid>41105c55-62ec-47bc-9dd0-c502cad68de6</guid>
    +    <class>
    +      <name>XWiki.TranslationDocumentClass</name>
    +      <customClass/>
    +      <customMapping/>
    +      <defaultViewSheet/>
    +      <defaultEditSheet/>
    +      <defaultWeb/>
    +      <nameField/>
    +      <validationScript/>
    +      <scope>
    +        <cache>0</cache>
    +        <disabled>0</disabled>
    +        <displayType>select</displayType>
    +        <freeText>forbidden</freeText>
    +        <largeStorage>0</largeStorage>
    +        <multiSelect>0</multiSelect>
    +        <name>scope</name>
    +        <number>1</number>
    +        <prettyName>Scope</prettyName>
    +        <relationalStorage>0</relationalStorage>
    +        <separator> </separator>
    +        <separators>|, </separators>
    +        <size>1</size>
    +        <unmodifiable>0</unmodifiable>
    +        <values>GLOBAL|WIKI|USER|ON_DEMAND</values>
    +        <classType>com.xpn.xwiki.objects.classes.StaticListClass</classType>
    +      </scope>
    +    </class>
    +    <property>
    +      <scope>WIKI</scope>
    +    </property>
    +  </object>
    +</xwikidoc>
    
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-ui/src/test/java/org/xwiki/realtime/ui/ConvertHTMLPageTest.java+118 0 added
    @@ -0,0 +1,118 @@
    +/*
    + * 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.realtime.ui;
    +
    +import javax.inject.Provider;
    +
    +import org.jsoup.nodes.Document;
    +import org.junit.jupiter.api.BeforeEach;
    +import org.junit.jupiter.api.Test;
    +import org.xwiki.csrf.script.CSRFTokenScriptService;
    +import org.xwiki.model.reference.DocumentReference;
    +import org.xwiki.rendering.RenderingScriptServiceComponentList;
    +import org.xwiki.rendering.internal.configuration.DefaultRenderingConfigurationComponentList;
    +import org.xwiki.script.service.ScriptService;
    +import org.xwiki.test.page.HTML50ComponentList;
    +import org.xwiki.test.page.PageTest;
    +import org.xwiki.test.page.XWikiSyntax21ComponentList;
    +
    +import com.xpn.xwiki.XWikiContext;
    +import com.xpn.xwiki.user.api.XWikiRightService;
    +
    +import static org.junit.jupiter.api.Assertions.assertEquals;
    +import static org.mockito.ArgumentMatchers.anyInt;
    +import static org.mockito.Mockito.mock;
    +import static org.mockito.Mockito.never;
    +import static org.mockito.Mockito.spy;
    +import static org.mockito.Mockito.verify;
    +import static org.mockito.Mockito.when;
    +
    +@RenderingScriptServiceComponentList
    +@DefaultRenderingConfigurationComponentList
    +@HTML50ComponentList
    +@XWikiSyntax21ComponentList
    +class ConvertHTMLPageTest extends PageTest
    +{
    +
    +    private static final String WIKI_NAME = "xwiki";
    +
    +    private static final String XWIKI_SPACE = "RTFrontend";
    +
    +    private static final DocumentReference RTF_FRONTEND_CONVERT_HTML =
    +        new DocumentReference(WIKI_NAME, XWIKI_SPACE, "ConvertHTML");
    +
    +    private static final String CSRF_TOKEN = "a0a0a0a0";
    +
    +    private CSRFTokenScriptService tokenService;
    +
    +    @BeforeEach
    +    void setUp() throws Exception
    +    {
    +        // Mock the Token Service to get a consistent CSRF token throughout the tests.
    +        this.tokenService = this.oldcore.getMocker().registerMockComponent(ScriptService.class, "csrf",
    +            CSRFTokenScriptService.class, true);
    +        when(this.tokenService.isTokenValid(CSRF_TOKEN)).thenReturn(true);
    +
    +        this.xwiki.initializeMandatoryDocuments(this.context);
    +
    +        this.context = mock(XWikiContext.class);
    +        Provider<XWikiContext> xcontextProvider =
    +            this.componentManager.registerMockComponent(XWikiContext.TYPE_PROVIDER);
    +        when(xcontextProvider.get()).thenReturn(this.context);
    +        when(this.context.getRequest()).thenReturn(this.request);
    +        when(this.context.getResponse()).thenReturn(this.response);
    +        when(this.context.getWiki()).thenReturn(this.xwiki);
    +
    +        // Fake programming access level to display the complete page.
    +        XWikiRightService rightService = this.oldcore.getMockRightService();
    +        when(this.xwiki.getRightService()).thenReturn(rightService);
    +        when(rightService.hasProgrammingRights(this.context)).thenReturn(true);
    +        this.response = spy(this.response);
    +        when(this.context.getResponse()).thenReturn(this.response);
    +    }
    +
    +    @Test
    +    void checkValidCSRFToken() throws Exception
    +    {
    +        when(this.context.getAction()).thenReturn("get");
    +        this.request.put("text", "Hello");
    +        this.request.put("form_token", CSRF_TOKEN);
    +        Document result = renderHTMLPage(RTF_FRONTEND_CONVERT_HTML);
    +
    +        verify(this.response, never()).setStatus(anyInt());
    +        verify(this.tokenService).isTokenValid(CSRF_TOKEN);
    +        assertEquals("$xwiki.getDocument('CKEditor.ContentSheet').getRenderedContent()",
    +            result.getElementsByTag("body").text());
    +    }
    +
    +    @Test
    +    void checkInvalidCSRFToken() throws Exception
    +    {
    +        String wrongToken = "wrong_token";
    +        when(this.context.getAction()).thenReturn("get");
    +        this.request.put("text", "Hello");
    +        this.request.put("form_token", wrongToken);
    +        Document result = renderHTMLPage(RTF_FRONTEND_CONVERT_HTML);
    +
    +        verify(this.response).sendError(403, "rtfFrontend.convertHtml.invalidCsrfToken");
    +        verify(this.tokenService).isTokenValid(wrongToken);
    +        assertEquals("", result.getElementsByTag("body").text());
    +    }
    +}
    
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-webjar/src/main/webjar/loader.js+5 1 modified
    @@ -71,7 +71,11 @@ define('xwiki-realtime-loader', [
         var userReference = xm.userReference ? XWiki.Model.serialize(xm.userReference) : 'xwiki:XWiki.XWikiGuest';
         return {
           WebsocketURL: realtimeConfig.webSocketURL,
    -      htmlConverterUrl: new XWiki.Document('ConvertHTML', 'RTFrontend').getURL('get', 'xpage=plain&outputSyntax=plain'),
    +      htmlConverterUrl: new XWiki.Document('ConvertHTML', 'RTFrontend').getURL('get', $.param({
    +        'xpage': 'plain',
    +        'outputSyntax': 'plain',
    +        'form_token': document.documentElement.dataset.xwikiFormToken
    +      })),
           // userId === <userReference>-encoded(<userName>)%2d<randomNumber>
           userName: userReference + '-' + encodeURIComponent(realtimeConfig.user.name + '-').replace(/-/g, '%2d') +
             String(Math.random()).substring(2),
    
d88da4572fb7

XWIKI-21424: Use CSRF token in the realtime HTML Converter API

https://github.com/xwiki/xwiki-platformpjeanjeanOct 10, 2023via ghsa
5 files changed · +230 4
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-ui/pom.xml+22 0 modified
    @@ -75,5 +75,27 @@
           <version>${project.version}</version>
           <scope>runtime</scope>
         </dependency>
    +    <!-- Test dependencies. -->
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-test-page</artifactId>
    +      <version>${project.version}</version>
    +      <scope>test</scope>
    +    </dependency>
    +    <!-- Provides the component list for RenderingScriptService. -->
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-rendering-xwiki</artifactId>
    +      <version>${project.version}</version>
    +      <type>test-jar</type>
    +      <scope>test</scope>
    +    </dependency>
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-rendering-configuration-default</artifactId>
    +      <version>${project.version}</version>
    +      <type>test-jar</type>
    +      <scope>test</scope>
    +    </dependency>
       </dependencies>
     </project>
    
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-ui/src/main/resources/RTFrontend/ConvertHTML.xml+8 3 modified
    @@ -20,7 +20,7 @@
      * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
     -->
     
    -<xwikidoc version="1.4" reference="RTFrontend.ConvertHTML" locale="">
    +<xwikidoc version="1.5" reference="RTFrontend.ConvertHTML" locale="">
       <web>RTFrontend</web>
       <name>ConvertHTML</name>
       <language/>
    @@ -52,8 +52,13 @@
       'documentReference': $documentReference
     })
     #if ($xcontext.action == 'get')
    -  ## FIXME: We shouldn't depend on CKEditor. This code should work independent of the configured WYSIWYG editor.
    -  $xwiki.getDocument('CKEditor.ContentSheet').getRenderedContent()
    +  ## Check that the CSRF token matches the user.
    +  #if (!$services.csrf.isTokenValid($request.form_token))
    +    $response.sendError(403, $services.localization.render('rtfFrontend.convertHtml.invalidCsrfToken'))
    +  #else
    +    ## FIXME: We shouldn't depend on CKEditor. This code should work independent of the configured WYSIWYG editor.
    +    $xwiki.getDocument('CKEditor.ContentSheet').getRenderedContent()
    +  #end
     #end
     {{/velocity}}</content>
     </xwikidoc>
    
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-ui/src/main/resources/XWiki/Realtime/Translations.xml+77 0 added
    @@ -0,0 +1,77 @@
    +<?xml version="1.1" encoding="UTF-8"?>
    +
    +<!--
    + * 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.
    +-->
    +
    +<xwikidoc version="1.5" reference="XWiki.Realtime.Translations" locale="">
    +  <web>XWiki.Realtime</web>
    +  <name>Translations</name>
    +  <language/>
    +  <defaultLanguage>en</defaultLanguage>
    +  <translation>0</translation>
    +  <creator>xwiki:XWiki.Admin</creator>
    +  <parent>Main.WebHome</parent>
    +  <author>xwiki:XWiki.Admin</author>
    +  <contentAuthor>xwiki:XWiki.Admin</contentAuthor>
    +  <version>1.1</version>
    +  <title/>
    +  <comment/>
    +  <minorEdit>false</minorEdit>
    +  <syntaxId>plain/1.0</syntaxId>
    +  <hidden>true</hidden>
    +  <content>rtfFrontend.convertHtml.invalidCsrfToken=Invalid CSRF Token</content>
    +  <object>
    +    <name>XWiki.Realtime.Translations</name>
    +    <number>0</number>
    +    <className>XWiki.TranslationDocumentClass</className>
    +    <guid>41105c55-62ec-47bc-9dd0-c502cad68de6</guid>
    +    <class>
    +      <name>XWiki.TranslationDocumentClass</name>
    +      <customClass/>
    +      <customMapping/>
    +      <defaultViewSheet/>
    +      <defaultEditSheet/>
    +      <defaultWeb/>
    +      <nameField/>
    +      <validationScript/>
    +      <scope>
    +        <cache>0</cache>
    +        <disabled>0</disabled>
    +        <displayType>select</displayType>
    +        <freeText>forbidden</freeText>
    +        <largeStorage>0</largeStorage>
    +        <multiSelect>0</multiSelect>
    +        <name>scope</name>
    +        <number>1</number>
    +        <prettyName>Scope</prettyName>
    +        <relationalStorage>0</relationalStorage>
    +        <separator> </separator>
    +        <separators>|, </separators>
    +        <size>1</size>
    +        <unmodifiable>0</unmodifiable>
    +        <values>GLOBAL|WIKI|USER|ON_DEMAND</values>
    +        <classType>com.xpn.xwiki.objects.classes.StaticListClass</classType>
    +      </scope>
    +    </class>
    +    <property>
    +      <scope>WIKI</scope>
    +    </property>
    +  </object>
    +</xwikidoc>
    
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-ui/src/test/java/org/xwiki/realtime/ui/ConvertHTMLPageTest.java+118 0 added
    @@ -0,0 +1,118 @@
    +/*
    + * 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.realtime.ui;
    +
    +import javax.inject.Provider;
    +
    +import org.jsoup.nodes.Document;
    +import org.junit.jupiter.api.BeforeEach;
    +import org.junit.jupiter.api.Test;
    +import org.xwiki.csrf.script.CSRFTokenScriptService;
    +import org.xwiki.model.reference.DocumentReference;
    +import org.xwiki.rendering.RenderingScriptServiceComponentList;
    +import org.xwiki.rendering.internal.configuration.DefaultRenderingConfigurationComponentList;
    +import org.xwiki.script.service.ScriptService;
    +import org.xwiki.test.page.HTML50ComponentList;
    +import org.xwiki.test.page.PageTest;
    +import org.xwiki.test.page.XWikiSyntax21ComponentList;
    +
    +import com.xpn.xwiki.XWikiContext;
    +import com.xpn.xwiki.user.api.XWikiRightService;
    +
    +import static org.junit.jupiter.api.Assertions.assertEquals;
    +import static org.mockito.ArgumentMatchers.anyInt;
    +import static org.mockito.Mockito.mock;
    +import static org.mockito.Mockito.never;
    +import static org.mockito.Mockito.spy;
    +import static org.mockito.Mockito.verify;
    +import static org.mockito.Mockito.when;
    +
    +@RenderingScriptServiceComponentList
    +@DefaultRenderingConfigurationComponentList
    +@HTML50ComponentList
    +@XWikiSyntax21ComponentList
    +class ConvertHTMLPageTest extends PageTest
    +{
    +
    +    private static final String WIKI_NAME = "xwiki";
    +
    +    private static final String XWIKI_SPACE = "RTFrontend";
    +
    +    private static final DocumentReference RTF_FRONTEND_CONVERT_HTML =
    +        new DocumentReference(WIKI_NAME, XWIKI_SPACE, "ConvertHTML");
    +
    +    private static final String CSRF_TOKEN = "a0a0a0a0";
    +
    +    private CSRFTokenScriptService tokenService;
    +
    +    @BeforeEach
    +    void setUp() throws Exception
    +    {
    +        // Mock the Token Service to get a consistent CSRF token throughout the tests.
    +        this.tokenService = this.oldcore.getMocker().registerMockComponent(ScriptService.class, "csrf",
    +            CSRFTokenScriptService.class, true);
    +        when(this.tokenService.isTokenValid(CSRF_TOKEN)).thenReturn(true);
    +
    +        this.xwiki.initializeMandatoryDocuments(this.context);
    +
    +        this.context = mock(XWikiContext.class);
    +        Provider<XWikiContext> xcontextProvider =
    +            this.componentManager.registerMockComponent(XWikiContext.TYPE_PROVIDER);
    +        when(xcontextProvider.get()).thenReturn(this.context);
    +        when(this.context.getRequest()).thenReturn(this.request);
    +        when(this.context.getResponse()).thenReturn(this.response);
    +        when(this.context.getWiki()).thenReturn(this.xwiki);
    +
    +        // Fake programming access level to display the complete page.
    +        XWikiRightService rightService = this.oldcore.getMockRightService();
    +        when(this.xwiki.getRightService()).thenReturn(rightService);
    +        when(rightService.hasProgrammingRights(this.context)).thenReturn(true);
    +        this.response = spy(this.response);
    +        when(this.context.getResponse()).thenReturn(this.response);
    +    }
    +
    +    @Test
    +    void checkValidCSRFToken() throws Exception
    +    {
    +        when(this.context.getAction()).thenReturn("get");
    +        this.request.put("text", "Hello");
    +        this.request.put("form_token", CSRF_TOKEN);
    +        Document result = renderHTMLPage(RTF_FRONTEND_CONVERT_HTML);
    +
    +        verify(this.response, never()).setStatus(anyInt());
    +        verify(this.tokenService).isTokenValid(CSRF_TOKEN);
    +        assertEquals("$xwiki.getDocument('CKEditor.ContentSheet').getRenderedContent()",
    +            result.getElementsByTag("body").text());
    +    }
    +
    +    @Test
    +    void checkInvalidCSRFToken() throws Exception
    +    {
    +        String wrongToken = "wrong_token";
    +        when(this.context.getAction()).thenReturn("get");
    +        this.request.put("text", "Hello");
    +        this.request.put("form_token", wrongToken);
    +        Document result = renderHTMLPage(RTF_FRONTEND_CONVERT_HTML);
    +
    +        verify(this.response).sendError(403, "rtfFrontend.convertHtml.invalidCsrfToken");
    +        verify(this.tokenService).isTokenValid(wrongToken);
    +        assertEquals("", result.getElementsByTag("body").text());
    +    }
    +}
    
  • xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-webjar/src/main/webjar/loader.js+5 1 modified
    @@ -71,7 +71,11 @@ define('xwiki-realtime-loader', [
         var userReference = xm.userReference ? XWiki.Model.serialize(xm.userReference) : 'xwiki:XWiki.XWikiGuest';
         return {
           WebsocketURL: realtimeConfig.webSocketURL,
    -      htmlConverterUrl: new XWiki.Document('ConvertHTML', 'RTFrontend').getURL('get', 'xpage=plain&outputSyntax=plain'),
    +      htmlConverterUrl: new XWiki.Document('ConvertHTML', 'RTFrontend').getURL('get', $.param({
    +        'xpage': 'plain',
    +        'outputSyntax': 'plain',
    +        'form_token': document.documentElement.dataset.xwikiFormToken
    +      })),
           // userId === <userReference>-encoded(<userName>)%2d<randomNumber>
           userName: userReference + '-' + encodeURIComponent(realtimeConfig.user.name + '-').replace(/-/g, '%2d') +
             String(Math.random()).substring(2),
    

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

News mentions

0

No linked articles in our index yet.