CVE-2023-40572 (Java, published 2023-08-24T02:15Z)
Description: value: XWiki Platform is a generic wiki platform offering runtime services for applications built on top of it. The create action is vulnerable to a CSRF attack, allowing script and thus remote code execution when targeting a user with script/programming right, thus compromising the confidentiality, integrity and availability of the whole XWiki installation. When a user with script right views this image and a log message `ERROR foo - Script executed!` appears in the log, the XWiki installation is vulnerable. This has been patched in XWiki 14.10.9 and 15.4RC1 by requiring a CSRF token for the actual page creation.
Severity: nan (CVSS v3 base score: 8)
Weakness: CWE-352 \u2014 Cross-Site Request Forgery (CSRF)
The web application does not, or can not, sufficiently verify whether a well-formed, valid, consistent request was intentionally provided by the user who submitted the request.
Repository: https://github.com/xwiki/xwiki-platform
Files changed:
xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/web/CreateAction.java
xwiki-platform-core/xwiki-platform-oldcore/src/test/java/com/xpn/xwiki/web/CreateActionTest.java
xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-templates/src/main/resources/templates/createinline.vm
Commit message: XWIKI-20849: Require a CSRF token in the create action


Vulnerable code:
            || !this.isEntityReferenceNameValid(newDocumentReference)) {
        CSRFToken csrf = Utils.getComponent(CSRFToken.class);
        redirectParams += "&form_token=" + Util.encodeURI(csrf.getToken(), null);
        String csrfTokenValue = "token42";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue,
        String csrfTokenValue = "token432";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, null,
        String csrfTokenValue = "token4234";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=&parent=Main.WebHome&title=X&form_token=" + csrfTokenValue, null, "xwiki",
        String csrfTokenValue = "token34342";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, null,
        String csrfTokenValue = "token4234343";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, null, "xwiki",
        String csrfTokenValue = "token424345";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, null,
        String csrfTokenValue = "token42124343";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=&parent=Main.WebHome&title=Z&form_token=" + csrfTokenValue, null,
        String csrfTokenValue = "token424334466";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, null, "xwiki",
        String csrfTokenValue = "token429988";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=&parent=Main.WebHome&title=Z&form_token=" + csrfTokenValue, null, "xwiki",
        String csrfTokenValue = "token42009";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, null, "xwiki",
        String csrfTokenValue = "token4233311";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, null, "xwiki",
        String csrfTokenValue = "token422112455";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=&parent=Main.WebHome&title=Z&form_token=" + csrfTokenValue, null, "xwiki",
        String csrfTokenValue = "token42778900";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=&parent=Main.WebHome&title=X&form_token=" + csrfTokenValue, null, "xwiki",
        String csrfTokenValue = "token4344119982";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=&parent=Main.WebHome&title=X&form_token=" + csrfTokenValue, null, "xwiki",
        String csrfTokenValue = "token425553";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=&parent=Main.WebHome&title=X.Y&form_token=" + csrfTokenValue, null,
        String csrfTokenValue = "token42008766";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, null, "xwiki",
        String csrfTokenValue = "token4221098";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=W&form_token=" + csrfTokenValue,
        String csrfTokenValue = "token42988733";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue,
        String csrfTokenValue = "token4222113555";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue,
        String csrfTokenValue = "token4200983331";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue,
        String csrfTokenValue = "token42234456";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue,
        String csrfTokenValue = "token4298833";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue,
        String csrfTokenValue = "token4244112";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue,
        String csrfTokenValue = "token422555987";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue,
        String csrfTokenValue = "token424111553";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue,
        String csrfTokenValue = "token42008733";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue,
        String csrfTokenValue = "token423366";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue,
        String csrfTokenValue = "token4265677398";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue,
        String csrfTokenValue = "token421198337";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue,
        String csrfTokenValue = "token429866333";
        when(this.csrfToken.getToken()).thenReturn(csrfTokenValue);
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue,

Fixed code:
import javax.inject.Inject;
    @Inject
    private CSRFToken csrf;

        // Also check the CSRF token.
            || !this.isEntityReferenceNameValid(newDocumentReference)
            || !this.csrf.isTokenValid(context.getRequest().getParameter("form_token")))
        {
        redirectParams += "&form_token=" + Util.encodeURI(this.csrf.getToken(), null);
    private static final String CSRF_TOKEN_VALUE = "token4234343";


        when(this.csrfToken.getToken()).thenReturn(CSRF_TOKEN_VALUE);
        when(this.csrfToken.isTokenValid(CSRF_TOKEN_VALUE)).thenReturn(true);
        when(this.mockRequest.getParameter("form_token")).thenReturn(CSRF_TOKEN_VALUE);
            "template=&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE,
    @Test
    void newDocumentFromURLWithInvalidToken() throws Exception
    {
        // new document = xwiki:X.Y
        DocumentReference documentReference = new DocumentReference("xwiki", Arrays.asList("X"), "Y");
        XWikiDocument document = mock(XWikiDocument.class);
        when(document.getDocumentReference()).thenReturn(documentReference);
        when(document.isNew()).thenReturn(true);
        when(document.getLocalReferenceMaxLength()).thenReturn(255);
        this.context.setDoc(document);

        // Submit an invalid token
        when(this.mockRequest.getParameter("form_token")).thenReturn("fakeToken");

        // Run the action
        String result = this.action.render(this.context);

        // The tests are below this line!

        // Verify that the create template is rendered, so the UI is displayed for the user to re-submit with the
        // form token.
        assertEquals("create", result);

        // Verify that we got until the token validation.
        verify(this.csrfToken).isTokenValid("fakeToken");

        // We should not get this far so no redirect should be done, just the template will be rendered.
        verify(this.mockURLFactory, never()).createURL(any(), any(), any(), any(), any(), any(),
            any(XWikiContext.class));
    }

        // Verify that the token has been validated.
        verify(this.csrfToken).isTokenValid(CSRF_TOKEN_VALUE);

            "template=&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null,
            "template=&parent=Main.WebHome&title=X&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki",
            "template=&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null,
            "template=&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki",
            "template=&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null,
            "template=&parent=Main.WebHome&title=Z&form_token=" + CSRF_TOKEN_VALUE, null,
            "template=&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki",
            "template=&parent=Main.WebHome&title=Z&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki",
            "template=&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki",
            "template=&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki",
            "template=&parent=Main.WebHome&title=Z&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki",
            "template=&parent=Main.WebHome&title=X&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki",
            "template=&parent=Main.WebHome&title=X&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki",
            "template=&parent=Main.WebHome&title=X.Y&form_token=" + CSRF_TOKEN_VALUE, null,
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki",
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=W&form_token=" + CSRF_TOKEN_VALUE,
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE,
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE,
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE,
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE,
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE,
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE,
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE,
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE,
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE,
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE,
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE,
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE,
            "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE,
  <input type="hidden" name="form_token" value="$!{escapetool.xml($services.csrf.getToken())}"/>