CVE-2023-35166 (published 2023-06-20T20:15Z)

XWiki Platform is a generic wiki platform offering runtime services for applications built on top of it. It's possible to execute any wiki content with the right of the TipsPanel author by creating a tip UI extension. This has been patched in XWiki 15.1-rc-1 and 14.10.5.\n

CVSS v3 base score: 8.8, HIGH (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)

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

Fix information:
repo_url: https://github.com/xwiki/xwiki-platform
commit_details: repo_url: https://github.com/xwiki/xwiki-platform
author: Thomas Mortagne
author_date: 2023-02-01 17:50:32+01:00
msg: XWIKI-20281: Improve tips rendering
repository: repo_url: https://github.com/xwiki/xwiki-platform
repo_name: xwiki/xwiki-platform
description: The XWiki platform
repo_language: Java
owner: xwiki
file_changes: filename: pom.xml
change_type: ModificationType.MODIFY
diff: @@ -34,4 +34,12 @@
   <modules>
     <module>xwiki-platform-help-ui</module>
   </modules>
+  <profiles>
+    <profile>
+      <id>integration-tests</id>
+      <modules>
+        <module>xwiki-platform-help-test</module>
+      </modules>
+    </profile>
+  </profiles>
 </project>

programming_language: HTML
filename: pom.xml
change_type: ModificationType.ADD
diff: @@ -0,0 +1,48 @@
+<?xml version="1.0" 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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.xwiki.platform</groupId>
+    <artifactId>xwiki-platform-help</artifactId>
+    <version>15.1-SNAPSHOT</version>
+  </parent>
+  <artifactId>xwiki-platform-help-test</artifactId>
+  <name>XWiki Platform - Panels - Help - Parent POM</name>
+  <packaging>pom</packaging>
+  <description>XWiki Platform - Help - Tests - Parent POM</description>
+  <properties>
+    <!-- Don't run backward-compatibility checks in test modules since we don't consider them as public APIs -->
+    <xwiki.revapi.skip>true</xwiki.revapi.skip>
+    <!-- Don't run Checkstyle in test modules -->
+    <xwiki.checkstyle.skip>true</xwiki.checkstyle.skip>
+  </properties>
+  <profiles>
+    <profile>
+      <id>docker</id>
+      <modules>
+        <module>xwiki-platform-panels-test-docker</module>
+      </modules>
+    </profile>
+  </profiles>
+</project>

programming_language: HTML
filename: pom.xml
change_type: ModificationType.ADD
diff: @@ -0,0 +1,116 @@
+<?xml version="1.0" 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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>xwiki-platform-help-test</artifactId>
+    <groupId>org.xwiki.platform</groupId>
+    <version>15.1-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>xwiki-platform-help-test-docker</artifactId>
+  <!-- TODO: Move to use "functional-test" in the future when http://jira.codehaus.org/browse/MNG-1911 is fixed,
+       see https://jira.xwiki.org/browse/XWIKI-7683 -->
+  <packaging>jar</packaging>
+  <name>XWiki Platform - Help - Tests - Functional Docker Tests</name>
+  <description>XWiki Platform - Help - Tests - Functional Tests in Docker</description>
+  <properties>
+    <!-- Functional tests are allowed to output content to the console -->
+    <xwiki.surefire.captureconsole.skip>true</xwiki.surefire.captureconsole.skip>
+  </properties>
+  <dependencies>
+    <!-- =========================================
+         Runtime Dependencies for tested features.
+         ========================================= -->
+    <dependency>
+      <groupId>org.xwiki.platform</groupId>
+      <artifactId>xwiki-platform-help-ui</artifactId>
+      <version>${project.version}</version>
+      <scope>runtime</scope>
+      <type>xar</type>
+    </dependency>
+    <dependency>
+      <groupId>org.xwiki.platform</groupId>
+      <artifactId>xwiki-platform-panels-ui</artifactId>
+      <version>${project.version}</version>
+      <scope>runtime</scope>
+      <type>xar</type>
+    </dependency>
+
+    <!-- ================================
+         Test only dependencies
+         ================================ -->
+    <dependency>
+      <groupId>org.xwiki.platform</groupId>
+      <artifactId>xwiki-platform-test-docker</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.xwiki.platform</groupId>
+      <artifactId>xwiki-platform-panels-test-pageobjects</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <testSourceDirectory>src/test/it</testSourceDirectory>
+    <plugins>
+      <!-- We need to explicitly include the failsafe plugin since it's not part of the default maven lifecycle -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-failsafe-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+  <profiles>
+    <profile>
+      <id>clover</id>
+      <!-- Add the Clover JAR to the WAR so that it's available at runtime when XWiki executes.
+           It's needed because instrumented jars in the WAR will call Clover APIs at runtime when they execute. -->
+      <dependencies>
+        <dependency>
+          <groupId>org.openclover</groupId>
+          <artifactId>clover</artifactId>
+        </dependency>
+      </dependencies>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-failsafe-plugin</artifactId>
+            <configuration>
+              <systemProperties combine.children="append">
+                <!-- Tell the Docker-based test to activate the Clover profile so that the Clover JAR is added to
+                     WEB-INF/lib -->
+                <property>
+                  <name>xwiki.test.ui.profiles</name>
+                  <value>clover</value>
+                </property>
+              </systemProperties>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+</project>
\ No newline at end of file

programming_language: HTML
filename: AllITs.java
change_type: ModificationType.ADD
diff: @@ -0,0 +1,39 @@
+/*
+ * 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.help.test.ui.docker;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.xwiki.test.docker.junit5.UITest;
+
+/**
+ * All UI Tests for the Help Application.
+ *
+ * @version $Id$
+ */
+@UITest
+class AllITs
+{
+    @Nested
+    @DisplayName("Tips panel")
+    class NestedPanelIT extends TipsPanelIT
+    {
+    }
+}

programming_language: Java
filename: TipsPanelIT.java
change_type: ModificationType.ADD
diff: @@ -0,0 +1,116 @@
+/*
+ * 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.help.test.ui.docker;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.xwiki.model.reference.DocumentReference;
+import org.xwiki.model.reference.LocalDocumentReference;
+import org.xwiki.panels.test.po.PanelViewPage;
+import org.xwiki.rendering.syntax.Syntax;
+import org.xwiki.rendering.wikimacro.internal.WikiMacroClassDocumentInitializer;
+import org.xwiki.rest.model.jaxb.Objects;
+import org.xwiki.rest.model.jaxb.Page;
+import org.xwiki.test.docker.junit5.TestReference;
+import org.xwiki.test.docker.junit5.UITest;
+import org.xwiki.test.ui.TestUtils;
+import org.xwiki.uiextension.internal.UIExtensionClassDocumentInitializer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.xwiki.test.ui.TestUtils.RestTestUtils.object;
+import static org.xwiki.test.ui.TestUtils.RestTestUtils.property;
+
+/**
+ * Validate the Tips panel.
+ *
+ * @version $Id$
+ */
+@UITest
+class TipsPanelIT
+{
+    private final static String TIPS_UIXP = "org.xwiki.platform.help.tipsPanel";
+
+    private final static String TIPS_UIXP_DISABLED = TIPS_UIXP + ".disabled";
+
+    @BeforeEach
+    void setUp(TestUtils testUtils)
+    {
+        testUtils.loginAsSuperAdmin();
+    }
+
+    @Test
+    @Order(1)
+    void verifyTipsPropertyIsRestricted(TestUtils testUtils, TestReference testReference) throws Exception
+    {
+        // Unregister all tips
+        switchUIXs(TIPS_UIXP, TIPS_UIXP_DISABLED, testUtils);
+
+        // Register a macro to check if the context is restricted
+        registerIsrestrictedMacro(testUtils);
+
+        // Create a tip with tip property
+        Page tipPage = testUtils.rest().page(testReference);
+        tipPage.setObjects(new Objects());
+        org.xwiki.rest.model.jaxb.Object tipObject = object(UIExtensionClassDocumentInitializer.CLASS_REFERENCE_STRING);
+        tipObject.getProperties().add(property("extensionPointId", "org.xwiki.platform.help.tipsPanel"));
+        tipObject.getProperties().add(property("parameters",
+            "tip=execution is restricted: {{isrestricted/}}"));
+        tipPage.getObjects().getObjectSummaries().add(tipObject);
+        testUtils.rest().save(tipPage);
+
+        // Execute the tip panel and verify the result is restricted (the velocity macro is forbidden)
+        testUtils.gotoPage(new DocumentReference("xwiki", "Help", "TipsPanel", "WebHome"));
+        PanelViewPage panelPage = new PanelViewPage();
+        assertEquals("execution is restricted: true", panelPage.getPanelContent().getText());
+
+        // Put back all tips
+        switchUIXs(TIPS_UIXP_DISABLED, TIPS_UIXP, testUtils);
+    }
+
+    private void switchUIXs(String oldid, String newid, TestUtils testUtils) throws Exception
+    {
+        testUtils.executeWiki(String.format(
+        // @formatter:off
+            "{{velocity}}\n"
+            + "#foreach($uix in $services.uix.getExtensions('%s'))\n"
+            + "  #set ($uixDocument = $xwiki.getDocument($uix.documentReference))\n"
+            + "  $uixDocument.set('extensionPointId', '%s')\n"
+            + "  $uixDocument.save()\n"
+            + "#end\n"
+            + "{{/velocity}}", oldid, newid)
+            // @formatter:on
+            , Syntax.XWIKI_2_1);
+    }
+
+    private void registerIsrestrictedMacro(TestUtils testUtils) throws Exception
+    {
+        LocalDocumentReference macroReference = new LocalDocumentReference("Test", "IsrestrictedMacro");
+        Page macroPage = testUtils.rest().page(macroReference);
+        macroPage.setObjects(new Objects());
+        org.xwiki.rest.model.jaxb.Object tipObject = object(WikiMacroClassDocumentInitializer.WIKI_MACRO_CLASS);
+        tipObject.getProperties().add(property("id", "isrestricted"));
+        tipObject.getProperties().add(property("supportsInlineMode", 1));
+        tipObject.getProperties().add(property("code",
+            "{{velocity}}$wikimacro.context.transformationContext.isRestricted(){{/velocity}}"));
+        macroPage.getObjects().getObjectSummaries().add(tipObject);
+        testUtils.rest().save(macroPage);
+    }
+}

programming_language: Java
filename: WebHome.xml
change_type: ModificationType.MODIFY
diff: @@ -173,7 +173,9 @@
 #set ($uixs = $services.uix.getExtensions('org.xwiki.platform.help.tipsPanel'))
 #if ($uixs.size() &gt; 0)
   #set ($index = $mathtool.random(0, $uixs.size()))
-  $uixs.get($index).getParameters().get('tip')
+  #set ($tip = $uixs.get($index).getParameters().get('tip'))
+  ## Execute the content in restricted mode as it's not executed with the right author
+  {{context restricted="true" transformationContext="transformations" source="script:tip"/}}
 #else
   $services.localization.render('help.tipsPanel.noTipMessage')
 #end

programming_language: TypeScript
filename: PanelViewPage.java
change_type: ModificationType.MODIFY
diff: @@ -19,6 +19,8 @@
  */
 package org.xwiki.panels.test.po;
 
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
 import org.xwiki.test.ui.po.ViewPage;
 
 /**
@@ -29,10 +31,22 @@
  */
 public class PanelViewPage extends ViewPage
 {
+    @FindBy(className = "xwikipanelcontents")
+    private WebElement content;
+
     @SuppressWarnings("unchecked")
     @Override
     protected PanelEditPage createInlinePage()
     {
         return new PanelEditPage();
     }
+
+    /**
+     * @since 15.1RC1
+     * @since 14.10.5
+     */
+    public WebElement getPanelContent()
+    {
+        return this.content;
+    }
 }

programming_language: Java
filename: TestUtils.java
change_type: ModificationType.MODIFY
diff: @@ -40,6 +40,7 @@
 import java.util.Objects;
 import java.util.Properties;
 import java.util.Set;
+import java.util.UUID;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -86,6 +87,7 @@
 import org.xwiki.model.reference.ObjectPropertyReference;
 import org.xwiki.model.reference.ObjectReference;
 import org.xwiki.model.reference.SpaceReference;
+import org.xwiki.rendering.syntax.Syntax;
 import org.xwiki.rest.model.jaxb.Page;
 import org.xwiki.rest.model.jaxb.Property;
 import org.xwiki.rest.model.jaxb.Xwiki;
@@ -1124,15 +1126,23 @@ public String getURL(EntityReference reference, String action, String queryStrin
      */
     public String executeAndGetBodyAsString(EntityReference reference, Map<String, ?> queryParameters) throws Exception
     {
-        String url = getURL(reference, "get", toQueryString(queryParameters));
-
-        GetMethod getMethod = executeGet(url);
+        gotoPage(getURL(reference, "get", toQueryString(queryParameters)));
+        
+        return getDriver().getPageSource();
+    }
 
-        String result = getMethod.getResponseBodyAsString();
+    /**
+     * @since 15.1RC1
+     * @since 14.10.5
+     */
+    public String executeWiki(String wikiContent, Syntax wikiSyntax) throws Exception
+    {
+        LocalDocumentReference reference =
+            new LocalDocumentReference(List.of("Test", "Execute"), UUID.randomUUID().toString());
 
-        getMethod.releaseConnection();
+        rest().savePage(reference, wikiContent, wikiSyntax.toIdString(), null, null);
 
-        return result;
+        return executeAndGetBodyAsString(reference, null);
     }
 
     /**
@@ -1595,9 +1605,11 @@ public String toQueryString(Map<String, ?> queryParameters)
     {
         StringBuilder builder = new StringBuilder();
 
-        for (Map.Entry<String, ?> entry : queryParameters.entrySet()) {
-            addQueryStringEntry(builder, entry.getKey(), entry.getValue());
-            builder.append('&');
+        if (queryParameters != null) {
+            for (Map.Entry<String, ?> entry : queryParameters.entrySet()) {
+                addQueryStringEntry(builder, entry.getKey(), entry.getValue());
+                builder.append('&');
+            }
         }
 
         return builder.toString();

programming_language: Java