CVE-2023-29523 (Java, published 2023-04-19T00:15Z)
Description: value: XWiki Platform is a generic wiki platform offering runtime services for applications built on top of it. Any user who can edit their own user profile can execute arbitrary script macros including Groovy and Python macros that allow remote code execution including unrestricted read and write access to all wiki contents. The same vulnerability can also be exploited in other contexts where the `display` method on a document is used to display a field with wiki syntax, for example in applications created using `App Within Minutes`. This has been patched in XWiki 13.10.11, 14.4.8, 14.10.2 and 15.0RC1. There is no workaround apart from upgrading.
Severity: nan (CVSS v3 base score: 8.8)
Weakness: CWE-74 \u2014 Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
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.
Repository: https://github.com/xwiki/xwiki-platform
Files changed:
xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/doc/XWikiDocument.java
xwiki-platform-core/xwiki-platform-oldcore/src/test/java/com/xpn/xwiki/doc/XWikiDocumentTest.java
Commit message: XWIKI-20327: Escape closing HTML macro in XWikiDocument#display


Vulnerable code:
            // Add the {{html}}{{/html}} only when result really contains html since it's not needed for pure text
            if (isInRenderingEngine && !is10Syntax(wrappingSyntaxId) && HTMLUtils.containsElementText(result)) {
                result.append("{{/html}}");

Fixed code:
    private static final String CLOSE_HTML_MACRO = "{{/html}}";

            // Add the {{html}}{{/html}} only when result really contains html or { which could be part of an XWiki
            // macro syntax since it's not needed for pure text
            if (isInRenderingEngine && !is10Syntax(wrappingSyntaxId)
                && (HTMLUtils.containsElementText(result) || result.indexOf("{") != -1))
            {
                // Escape closing HTML macro syntax.
                int startIndex = 0;
                // Start searching at the last match to avoid scanning the whole string again.
                while ((startIndex = result.indexOf(CLOSE_HTML_MACRO, startIndex)) != -1) {
                    result.replace(startIndex, startIndex + 2, "&#123;&#123;");
                }
                result.append(CLOSE_HTML_MACRO);
import com.xpn.xwiki.objects.classes.PropertyClass;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.doAnswer;
    @Test
    void displayEscapesClosingHTMLMacro()
    {
        this.oldcore.getXWikiContext().put("isInRenderingEngine", true);
        when(this.xWiki.getCurrentContentSyntaxId(any())).thenReturn("xwiki/2.1");
        this.document.setSyntax(Syntax.XWIKI_2_0);

        BaseObject object = mock(BaseObject.class);
        when(object.getOwnerDocument()).thenReturn(this.document);

        BaseClass xClass = mock(BaseClass.class);
        when(object.getXClass(any())).thenReturn(xClass);
        PropertyClass propertyInterface = mock(PropertyClass.class);
        when(xClass.get("mock")).thenReturn(propertyInterface);
        doAnswer(call -> {
            call.getArgument(0, StringBuffer.class).append("{{/html}}content{{/html}}");
            return null;
        }).when(propertyInterface).displayView(any(StringBuffer.class), eq("mock"), any(String.class), eq(object),
            anyBoolean(), any(XWikiContext.class));

        assertEquals("{{html clean=\"false\" wiki=\"false\"}}&#123;&#123;/html}}content&#123;&#123;/html}}{{/html}}",
            this.document.display("mock", "view", object, this.oldcore.getXWikiContext()));
    }