VYPR
Critical severityNVD Advisory· Published Aug 23, 2023· Updated Oct 3, 2024

XWiki Platform privilege escalation (PR) from account through AWM content fields

CVE-2023-40177

Description

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.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.xwiki.platform:xwiki-platform-appwithinminutes-uiMaven
>= 4.3-milestone-2, < 14.10.514.10.5

Affected products

1

Patches

1
dfb1cde173e3

XWIKI-19906: Render the AppWithinMinutes Content field as its author

https://github.com/xwiki/xwiki-platformMarius Dumitru FloreaFeb 15, 2023via ghsa
2 files changed · +41 15
  • 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+34 11 modified
    @@ -23,6 +23,7 @@
     
     import org.apache.commons.lang3.RandomStringUtils;
     import org.junit.jupiter.api.BeforeAll;
    +import org.junit.jupiter.api.Order;
     import org.junit.jupiter.api.Test;
     import org.xwiki.appwithinminutes.test.po.ApplicationClassEditPage;
     import org.xwiki.appwithinminutes.test.po.ApplicationCreatePage;
    @@ -51,14 +52,15 @@
      * @since 13.10RC1
      */
     @UITest(properties = {
    -    // Exclude the AppWithinMinutes.ClassEditSheet and AppWithinMinutes.DynamicMessageTool from the PR checker since 
    +    // Exclude the AppWithinMinutes.ClassEditSheet and AppWithinMinutes.DynamicMessageTool from the PR checker since
         // they use the groovy macro which requires PR rights.
         // TODO: Should be removed once XWIKI-20529 is closed.
         // Exclude AppWithinMinutes.LiveTableEditSheet because it calls com.xpn.xwiki.api.Document.saveWithProgrammingRights
    -    "xwikiPropertiesAdditionalProperties=test.prchecker.excludePattern=.*:AppWithinMinutes\\.(ClassEditSheet|DynamicMessageTool|LiveTableEditSheet)"
    -})
    +    "xwikiPropertiesAdditionalProperties=test.prchecker.excludePattern=.*:AppWithinMinutes\\.(ClassEditSheet|DynamicMessageTool|LiveTableEditSheet)"})
     class DocumentFieldsIT
     {
    +    private String appName = RandomStringUtils.randomAlphabetic(6);
    +
         @BeforeAll
         static void beforeAll(TestUtils setup)
         {
    @@ -73,14 +75,12 @@ static void beforeAll(TestUtils setup)
         }
     
         @Test
    +    @Order(1)
         void titleAndContent(TestUtils setup)
         {
    -        setup.loginAsAdmin();
    -
             // Create a new application.
    -        String appName = RandomStringUtils.randomAlphabetic(6);
             ApplicationCreatePage appCreatePage = ApplicationCreatePage.gotoPage();
    -        appCreatePage.setApplicationName(appName);
    +        appCreatePage.setApplicationName(this.appName);
             ApplicationClassEditPage classEditPage = appCreatePage.clickNextStep();
     
             // Add a standard field.
    @@ -126,30 +126,53 @@ void titleAndContent(TestUtils setup)
             assertTrue(entryViewPage.getContent().contains("Bar"));
     
             // Verify that we can edit the document fields in-place.
    -        String propertyReference = String.format("%s.Code.%1$sClass[0].title1", appName);
    +        String propertyReference = String.format("%s.Code.%1$sClass[0].title1", this.appName);
             EditablePropertyPane<String> titleProperty = new EditablePropertyPane<>(propertyReference);
             assertEquals("Foo", titleProperty.clickEdit().getValue());
             titleProperty.setValue("Book").clickSave();
             assertEquals("Book", titleProperty.getDisplayValue());
     
             // Check the entries live table.
    -        entryViewPage.clickBreadcrumbLink(appName);
    +        entryViewPage.clickBreadcrumbLink(this.appName);
             LiveTableElement liveTable = new ApplicationHomePage().getEntriesLiveTable();
             liveTable.waitUntilReady();
             assertEquals(1, liveTable.getRowCount());
             assertTrue(liveTable.hasRow("My Title", "Book"));
             assertTrue(liveTable.hasRow("My Content", "Bar"));
     
             // Check that the title and the content of the class have not been changed.
    -        setup.gotoPage(new LocalDocumentReference(Arrays.asList(appName, "Code"), appName + "Class"), "edit",
    +        setup.gotoPage(new LocalDocumentReference(Arrays.asList(this.appName, "Code"), this.appName + "Class"), "edit",
                 "editor=wiki");
             WikiEditPage editPage = new WikiEditPage();
    -        assertEquals(appName + " Class", editPage.getTitle());
    +        assertEquals(this.appName + " Class", editPage.getTitle());
             assertEquals("", editPage.getContent());
     
             // Now edit the class and check if the default values for title and content are taken from the template.
             editPage.edit();
             assertEquals(defaultTitle, new ClassFieldEditPane("title1").getDefaultValue());
             assertEquals(defaultContent, new ClassFieldEditPane("content1").getDefaultValue());
         }
    +
    +    @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"));
    +    }
     }
    
  • xwiki-platform-core/xwiki-platform-appwithinminutes/xwiki-platform-appwithinminutes-ui/src/main/resources/AppWithinMinutes/Content.xml+7 4 modified
    @@ -20,7 +20,7 @@
      * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
     -->
     
    -<xwikidoc version="1.2" reference="AppWithinMinutes.Content" locale="">
    +<xwikidoc version="1.5" reference="AppWithinMinutes.Content" locale="">
       <web>AppWithinMinutes</web>
       <name>Content</name>
       <language/>
    @@ -76,9 +76,12 @@
       #end
       {{/html}}
     #elseif ("$!type" != '')
    -  ## 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}}
    +  ## 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}}
     #else
       The display mode is not specified!
     #end
    

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

5

News mentions

0

No linked articles in our index yet.