CVE-2023-40177 (XML, published 2023-08-23T21:15Z)
Description: value: XWiki Platform is a generic wiki platform offering runtime services for applications built on top of it. Any registered user can use the content field of their user profile page to execute arbitrary scripts with programming rights, thus effectively performing rights escalation. This issue is present since version 4.3M2 when AppWithinMinutes Application added support for the Content field, allowing any wiki page (including the user profile page) to use its content as an AWM Content field, which has a custom displayer that executes the content with the rights of the ``AppWithinMinutes.Content`` author, rather than the rights of the content author. The vulnerability has been fixed in XWiki 14.10.5 and 15.1RC1. The fix is in the content of the AppWithinMinutes.Content page that defines the custom displayer. By using the ``display`` script service to render the content we make sure that the proper author is used for access rights checks.
Severity: nan (CVSS v3 base score: 8.8)
Weakness: CWE-94 \u2014 Improper Control of Generation of Code ('Code Injection')
The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.
Repository: https://github.com/xwiki/xwiki-platform
Files changed:
xwiki-platform-core/xwiki-platform-appwithinminutes/xwiki-platform-appwithinminutes-test/xwiki-platform-appwithinminutes-test-docker/src/test/it/org/xwiki/appwithinminutes/test/ui/DocumentFieldsIT.java
xwiki-platform-core/xwiki-platform-appwithinminutes/xwiki-platform-appwithinminutes-ui/src/main/resources/AppWithinMinutes/Content.xml
Commit message: XWIKI-19906: Render the AppWithinMinutes Content field as its author


Vulnerable code:
    // Exclude the AppWithinMinutes.ClassEditSheet and AppWithinMinutes.DynamicMessageTool from the PR checker since 
    "xwikiPropertiesAdditionalProperties=test.prchecker.excludePattern=.*:AppWithinMinutes\\.(ClassEditSheet|DynamicMessageTool|LiveTableEditSheet)"
})
        setup.loginAsAdmin();

        String appName = RandomStringUtils.randomAlphabetic(6);
        appCreatePage.setApplicationName(appName);
        String propertyReference = String.format("%s.Code.%1$sClass[0].title1", appName);
        entryViewPage.clickBreadcrumbLink(appName);
        setup.gotoPage(new LocalDocumentReference(Arrays.asList(appName, "Code"), appName + "Class"), "edit",
        assertEquals(appName + " Class", editPage.getTitle());
<xwikidoc version="1.2" reference="AppWithinMinutes.Content" locale="">
  ## Include the content of the current document.
  ## Escape {{ in the rendered content to be sure that the HTML macro is not closed unintentionally.
  {{html}}$tdoc.getRenderedContent($tdoc.content, $tdoc.syntax.toIdString()).replace('{{', '&amp;amp;#123;&amp;amp;#123;'){{/html}}

Fixed code:
import org.junit.jupiter.api.Order;
    // Exclude the AppWithinMinutes.ClassEditSheet and AppWithinMinutes.DynamicMessageTool from the PR checker since
    "xwikiPropertiesAdditionalProperties=test.prchecker.excludePattern=.*:AppWithinMinutes\\.(ClassEditSheet|DynamicMessageTool|LiveTableEditSheet)"})
    private String appName = RandomStringUtils.randomAlphabetic(6);

    @Order(1)
        appCreatePage.setApplicationName(this.appName);
        String propertyReference = String.format("%s.Code.%1$sClass[0].title1", this.appName);
        entryViewPage.clickBreadcrumbLink(this.appName);
        setup.gotoPage(new LocalDocumentReference(Arrays.asList(this.appName, "Code"), this.appName + "Class"), "edit",
        assertEquals(this.appName + " Class", editPage.getTitle());

    @Test
    @Order(2)
    void contentFromSimpleUser(TestUtils setup)
    {
        // Create an application entry with a simple user that doesn't have script rights.
        setup.createUserAndLogin("Alice", "pass");

        ApplicationHomePage appHomePage = ApplicationHomePage.gotoPage(this.appName);
        appHomePage.getEntriesLiveTable().waitUntilReady();

        EntryNamePane entryNamePage = appHomePage.clickAddNewEntry();
        entryNamePage.setName("ByAlice");

        EntryEditPage entryEditPage = entryNamePage.clickAdd();
        entryEditPage.setTitle("Title by $services.localization.render('Alice')");
        entryEditPage.setContent("Content by {{velocity}}$services.localization.render('Alice'){{/velocity}}");

        ViewPage entryViewPage = entryEditPage.clickSaveAndView();
        assertEquals("Title by $services.localization.render('Alice')", entryViewPage.getDocumentTitle());
        assertTrue(entryViewPage.getContent().contains("Content by"));
        assertTrue(entryViewPage.getContent().contains("The execution of the [velocity] script macro is not allowed"));
    }
<xwikidoc version="1.5" reference="AppWithinMinutes.Content" locale="">
  ## Display the content of the current document without using any sheet. We can't use the include macro here (with the
  ## author parameter) because the content may have unsaved changes (e.g. on preview action). We make sure that the HTML
  ## macro is not closed unintentionally, even though the XHTML printer protects us against this, just to be extra safe.
  {{html}}$services.display.content($tdoc, {
    'displayerHint': 'default'
  }).replace('{{/html}}', '&amp;amp;#123;&amp;amp;#123;/html&amp;amp;#125;&amp;amp;#125;'){{/html}}