CVE-2023-29514: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection') (CWE-74)
value: XWiki Platform is a generic wiki platform offering runtime services for applications built on top of it. Any user with edit rights on any document (e.g., their own user profile) can execute code with programming rights, leading to remote code execution. This vulnerability has been patched in XWiki 13.10.11, 14.4.8, 14.10.1 and 15.0 RC1. Users are advised to upgrade. There are no known workarounds for this vulnerability.
CWE description: The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component.
CVSS v3 base score: 8.8
Published: 2023-04-19T00:15Z
Repository: https://github.com/xwiki/xwiki-platform
Language: XML
Files changed: xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-test/xwiki-platform-administration-test-docker/src/test/it/org/xwiki/administration/test/ui/PageTemplatesIT.java, xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/AdminTemplatesSheet.xml
Commit date: 2022-12-01 18:09:50 +0100
Commit message: XWIKI-20268: Improve escaping in AdminTemplatesSheet

Diff: diff --git a/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-test/xwiki-platform-administration-test-docker/src/test/it/org/xwiki/administration/test/ui/PageTemplatesIT.java b/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-test/xwiki-platform-administration-test-docker/src/test/it/org/xwiki/administration/test/ui/PageTemplatesIT.java
index e82a785676fd9..9f135ebac23e3 100644
--- a/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-test/xwiki-platform-administration-test-docker/src/test/it/org/xwiki/administration/test/ui/PageTemplatesIT.java
+++ b/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-test/xwiki-platform-administration-test-docker/src/test/it/org/xwiki/administration/test/ui/PageTemplatesIT.java
@@ -23,10 +23,11 @@
 import java.util.List;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Order;
 import org.junit.jupiter.api.Test;
+import org.openqa.selenium.WebElement;
 import org.xwiki.administration.test.po.TemplateProviderInlinePage;
 import org.xwiki.administration.test.po.TemplatesAdministrationSectionPage;
 import org.xwiki.model.reference.DocumentReference;
 import org.xwiki.model.reference.EntityReference;
 import org.xwiki.model.reference.LocalDocumentReference;
@@ -356,10 +357,33 @@ void createPageFromForbiddenTemplate(TestUtils setup, TestReference testReferenc
 
         viewPage = wikiEditPage.clickSaveAndView();
         assertEquals("Some content in that page", viewPage.getContent());
     }
 
+    /**
+     * The goal of this test is to check that the template provider's title is correctly escaped.
+     */
+    @Test
+    @Order(5)
+    void templateProviderTitleEscaping(TestUtils setup, TestReference testReference) throws Exception
+    {
+        cleanUp(setup, testReference);
+
+        // Create a template
+        String templateContent = "Templates are fun";
+        String providerName = "{{html}}<span>HTML</span>{{/html}}";
+        LocalDocumentReference templateProviderReference = new LocalDocumentReference(providerName,
+            testReference.getLocalDocumentReference().getParent());
+        createTemplateAndTemplateProvider(setup, templateProviderReference, templateContent,
+            "Funny templates", true);
+
+        TemplatesAdministrationSectionPage adminPage = TemplatesAdministrationSectionPage.gotoPage();
+        List<WebElement> links = adminPage.getExistingTemplatesLinks();
+        assertFalse(links.stream().anyMatch(element -> element.getText().equals("HTML")));
+        assertTrue(links.stream().anyMatch(element -> providerName.equals(element.getText())));
+    }
+
     /**
      * Helper function to Create both a Template and a Template Provider for the tests in this class.
      */
     private ViewPage createTemplateAndTemplateProvider(TestUtils setup,
         LocalDocumentReference templateProviderReference, String templateContent, String templateTitle,
diff --git a/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/AdminTemplatesSheet.xml b/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/AdminTemplatesSheet.xml
index ca288664f7495..5361fb40a4dde 100644
--- a/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/AdminTemplatesSheet.xml
+++ b/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/AdminTemplatesSheet.xml
@@ -110,11 +110,11 @@
   (% class="col-xs-12 col-md-6" %)(((
   (% id="HAdminTemplatesProvidersList" %)
   == {{translation key="admin.templates.providerslist"/}} ==
 
     #foreach($providerFullname in $availableProviders)
-      * [[$services.rendering.escape($xwiki.getDocument($providerFullname).plainTitle, $xwiki.currentContentSyntaxId)&gt;&gt;$providerFullname]]
+      * [[$services.rendering.escape($services.rendering.escape($xwiki.getDocument($providerFullname).plainTitle, $xwiki.currentContentSyntaxId), $xwiki.currentContentSyntaxId)&gt;&gt;$services.rendering.escape($providerFullname, $xwiki.currentContentSyntaxId)]]
     #end
   )))
 #end
 
 {{/velocity}}</content>

Vulnerable code:       * [[$services.rendering.escape($xwiki.getDocument($providerFullname).plainTitle, $xwiki.currentContentSyntaxId)&gt;&gt;$providerFullname]]
Fixed code: import org.openqa.selenium.WebElement;
    /**
     * The goal of this test is to check that the template provider's title is correctly escaped.
     */
    @Test
    @Order(5)
    void templateProviderTitleEscaping(TestUtils setup, TestReference testReference) throws Exception
    {
        cleanUp(setup, testReference);

        // Create a template
        String templateContent = "Templates are fun";
        String providerName = "{{html}}<span>HTML</span>{{/html}}";
        LocalDocumentReference templateProviderReference = new LocalDocumentReference(providerName,
            testReference.getLocalDocumentReference().getParent());
        createTemplateAndTemplateProvider(setup, templateProviderReference, templateContent,
            "Funny templates", true);

        TemplatesAdministrationSectionPage adminPage = TemplatesAdministrationSectionPage.gotoPage();
        List<WebElement> links = adminPage.getExistingTemplatesLinks();
        assertFalse(links.stream().anyMatch(element -> element.getText().equals("HTML")));
        assertTrue(links.stream().anyMatch(element -> providerName.equals(element.getText())));
    }

      * [[$services.rendering.escape($services.rendering.escape($xwiki.getDocument($providerFullname).plainTitle, $xwiki.currentContentSyntaxId), $xwiki.currentContentSyntaxId)&gt;&gt;$services.rendering.escape($providerFullname, $xwiki.currentContentSyntaxId)]]