XWiki Platform vulnerable to CSRF privilege escalation/RCE via the create action
Description
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.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.xwiki.platform:xwiki-platform-oldcoreMaven | >= 3.2-milestone-3, < 14.10.9 | 14.10.9 |
org.xwiki.platform:xwiki-platform-oldcoreMaven | >= 15.0-rc-1, < 15.4-rc-1 | 15.4-rc-1 |
Affected products
1- Range: >= 3.2-milestone-3, < 14.10.9
Patches
24b20528808d0XWIKI-20849: Require a CSRF token in the create action
3 files changed · +80 −93
xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/web/CreateAction.java+9 −3 modified@@ -23,6 +23,7 @@ import java.util.Locale; import java.util.Map; +import javax.inject.Inject; import javax.inject.Named; import javax.inject.Provider; import javax.inject.Singleton; @@ -96,6 +97,9 @@ public class CreateAction extends XWikiAction */ private static final String LOCAL_SERIALIZER_HINT = "local"; + @Inject + private CSRFToken csrf; + /** * The action to perform when creating a new page from a template. * @@ -185,9 +189,12 @@ public String render(XWikiContext context) throws XWikiException checkRights(newDocumentReference.getLastSpaceReference(), context); // Check if the document to create already exists and if it respects the name strategy + // Also check the CSRF token. XWikiDocument newDocument = context.getWiki().getDocument(newDocumentReference, context); if (handler.isDocumentAlreadyExisting(newDocument) || handler.isDocumentPathTooLong(newDocumentReference) - || !this.isEntityReferenceNameValid(newDocumentReference)) { + || !this.isEntityReferenceNameValid(newDocumentReference) + || !this.csrf.isTokenValid(context.getRequest().getParameter("form_token"))) + { return CREATE_TEMPLATE; } @@ -334,8 +341,7 @@ private String getRedirectParameters(String parent, String title, String templat redirectParams += "&title=" + Util.encodeURI(title, null); } // Both the save and the edit action might require a CSRF token - CSRFToken csrf = Utils.getComponent(CSRFToken.class); - redirectParams += "&form_token=" + Util.encodeURI(csrf.getToken(), null); + redirectParams += "&form_token=" + Util.encodeURI(this.csrf.getToken(), null); return redirectParams; }
xwiki-platform-core/xwiki-platform-oldcore/src/test/java/com/xpn/xwiki/web/CreateActionTest.java+70 −90 modified@@ -72,6 +72,8 @@ @OldcoreTest class CreateActionTest { + private static final String CSRF_TOKEN_VALUE = "token4234343"; + @InjectMockitoOldcore MockitoOldcore oldcore; @@ -125,6 +127,10 @@ public void beforeEach() throws Exception when(this.mockRequest.get("type")).thenReturn("plain"); this.oldcore.getMocker().registerMockComponent(ObservationManager.class); + + 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); } @Test @@ -137,8 +143,6 @@ void newDocumentFromURL() throws Exception when(document.isNew()).thenReturn(true); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token42"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Run the action String result = action.render(context); @@ -149,11 +153,42 @@ void newDocumentFromURL() throws Exception assertNull(result); verify(mockURLFactory).createURL("X", "Y", "edit", - "template=&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, + "template=&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } + @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)); + } + @Test void newDocumentButNonTerminalFromURL() throws Exception { @@ -164,8 +199,6 @@ void newDocumentButNonTerminalFromURL() throws Exception when(document.isNew()).thenReturn(true); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token432"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Pass the tocreate=nonterminal request parameter when(mockRequest.getParameter("tocreate")).thenReturn("nonterminal"); @@ -178,8 +211,11 @@ void newDocumentButNonTerminalFromURL() throws Exception // Verify null is returned (this means the response has been returned) assertNull(result); + // Verify that the token has been validated. + verify(this.csrfToken).isTokenValid(CSRF_TOKEN_VALUE); + verify(mockURLFactory).createURL("X.Y", "WebHome", "edit", - "template=&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, null, + "template=&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -216,8 +252,6 @@ void newDocumentWebHomeTopLevelFromURL() throws Exception when(document.isNew()).thenReturn(true); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token4234"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Run the action String result = action.render(context); @@ -229,7 +263,7 @@ void newDocumentWebHomeTopLevelFromURL() throws Exception // Note: The title is not "WebHome", but "X" (the space's name) to avoid exposing "WebHome" in the UI. verify(mockURLFactory).createURL("X", "WebHome", "edit", - "template=&parent=Main.WebHome&title=X&form_token=" + csrfTokenValue, null, "xwiki", + "template=&parent=Main.WebHome&title=X&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -243,8 +277,6 @@ void newDocumentWebHomeFromURL() throws Exception when(document.isNew()).thenReturn(true); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token34342"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Run the action String result = action.render(context); @@ -257,7 +289,7 @@ void newDocumentWebHomeFromURL() throws Exception // Note1: The bebavior is the same for both a top level space and a child space WebHome. // Note2: The title is not "WebHome", but "Y" (the space's name) to avoid exposing "WebHome" in the UI. verify(mockURLFactory).createURL("X.Y", "WebHome", "edit", - "template=&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, null, + "template=&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -271,8 +303,6 @@ void newDocumentWebHomeButTerminalFromURL() throws Exception when(document.isNew()).thenReturn(true); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token4234343"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Pass the tocreate=terminal request parameter when(mockRequest.getParameter("tocreate")).thenReturn("terminal"); @@ -287,7 +317,7 @@ void newDocumentWebHomeButTerminalFromURL() throws Exception // Note: We are creating X.Y instead of X.Y.WebHome because the tocreate parameter says "terminal". verify(mockURLFactory).createURL("X", "Y", "edit", - "template=&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, null, "xwiki", + "template=&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -355,8 +385,6 @@ void existingDocumentFromUI() throws Exception when(document.isNew()).thenReturn(false); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token424345"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI spaceReference=X&name=Y when(mockRequest.getParameter("spaceReference")).thenReturn("X"); @@ -372,7 +400,7 @@ void existingDocumentFromUI() throws Exception // Note: We are creating X.Y.WebHome since we default to non-terminal documents. verify(mockURLFactory).createURL("X.Y", "WebHome", "edit", - "template=&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, null, + "template=&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -386,8 +414,6 @@ void existingDocumentFromUICheckEscaping() throws Exception when(document.isNew()).thenReturn(false); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token42124343"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI spaceReference=X.Y&name=Z when(mockRequest.getParameter("spaceReference")).thenReturn("X.Y"); @@ -403,7 +429,7 @@ void existingDocumentFromUICheckEscaping() throws Exception // Note: We are creating X.Y.Z.WebHome since we default to non-terminal documents. verify(mockURLFactory).createURL("X.Y.Z", "WebHome", "edit", - "template=&parent=Main.WebHome&title=Z&form_token=" + csrfTokenValue, null, + "template=&parent=Main.WebHome&title=Z&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -417,8 +443,6 @@ void existingDocumentTerminalFromUI() throws Exception when(document.isNew()).thenReturn(false); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token424334466"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI spaceReference=X&name=Y&tocreate=terminal when(mockRequest.getParameter("spaceReference")).thenReturn("X"); @@ -435,7 +459,7 @@ void existingDocumentTerminalFromUI() throws Exception // Note: We are creating X.Y instead of X.Y.WebHome because the tocreate parameter says "terminal". verify(mockURLFactory).createURL("X", "Y", "edit", - "template=&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, null, "xwiki", + "template=&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -449,8 +473,6 @@ void existingDocumentTerminalFromUICheckEscaping() throws Exception when(document.isNew()).thenReturn(false); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token429988"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI spaceReference=X.Y&name=Z&tocreate=termina when(mockRequest.getParameter("spaceReference")).thenReturn("X.Y"); @@ -467,7 +489,7 @@ void existingDocumentTerminalFromUICheckEscaping() throws Exception // Note: We are creating X.Y.Z instead of X.Y.Z.WebHome because the tocreate parameter says "terminal". verify(mockURLFactory).createURL("X.Y", "Z", "edit", - "template=&parent=Main.WebHome&title=Z&form_token=" + csrfTokenValue, null, "xwiki", + "template=&parent=Main.WebHome&title=Z&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -581,8 +603,6 @@ void existingDocumentFromUITopLevelDocument() throws Exception when(document.isNew()).thenReturn(false); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token42009"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI name=Y when(mockRequest.getParameter("name")).thenReturn("Y"); @@ -597,7 +617,7 @@ void existingDocumentFromUITopLevelDocument() throws Exception // Note: We are creating X.Y.WebHome since we default to non-terminal documents. verify(mockURLFactory).createURL("Y", "WebHome", "edit", - "template=&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, null, "xwiki", + "template=&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -615,8 +635,6 @@ void existingDocumentFromUIDeprecated() throws Exception when(document.isNew()).thenReturn(false); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token4233311"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI space=X&page=Y when(mockRequest.getParameter("space")).thenReturn("X"); @@ -632,7 +650,7 @@ void existingDocumentFromUIDeprecated() throws Exception // Note: We are creating X.Y since the deprecated parameters were creating terminal documents by default. verify(mockURLFactory).createURL("X", "Y", "edit", - "template=&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, null, "xwiki", + "template=&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -646,8 +664,6 @@ void existingDocumentFromUIDeprecatedCheckEscaping() throws Exception when(document.isNew()).thenReturn(false); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token422112455"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI space=X.Y&page=Z when(mockRequest.getParameter("space")).thenReturn("X.Y"); @@ -664,7 +680,7 @@ void existingDocumentFromUIDeprecatedCheckEscaping() throws Exception // Note1: The space parameter was previously considered as space name, not space reference, so it is escaped. // Note2: We are creating X\.Y.Z since the deprecated parameters were creating terminal documents by default. verify(mockURLFactory).createURL("X\\.Y", "Z", "edit", - "template=&parent=Main.WebHome&title=Z&form_token=" + csrfTokenValue, null, "xwiki", + "template=&parent=Main.WebHome&title=Z&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -678,8 +694,6 @@ void existingDocumentNonTerminalFromUIDeprecated() throws Exception when(document.isNew()).thenReturn(false); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token42778900"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI space=X&tocreate=space when(mockRequest.getParameter("space")).thenReturn("X"); @@ -695,7 +709,7 @@ void existingDocumentNonTerminalFromUIDeprecated() throws Exception // Note: We are creating X.WebHome because the tocreate parameter says "space". verify(mockURLFactory).createURL("X", "WebHome", "edit", - "template=&parent=Main.WebHome&title=X&form_token=" + csrfTokenValue, null, "xwiki", + "template=&parent=Main.WebHome&title=X&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -709,8 +723,6 @@ void existingDocumentNonTerminalFromUIDeprecatedIgnoringPage() throws Exception when(document.isNew()).thenReturn(false); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token4344119982"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI space=X&page=Y&tocreate=space when(mockRequest.getParameter("space")).thenReturn("X"); @@ -728,7 +740,7 @@ void existingDocumentNonTerminalFromUIDeprecatedIgnoringPage() throws Exception // Note: We are creating X.WebHome instead of X.Y because the tocreate parameter says "space" and the page // parameter is ignored. verify(mockURLFactory).createURL("X", "WebHome", "edit", - "template=&parent=Main.WebHome&title=X&form_token=" + csrfTokenValue, null, "xwiki", + "template=&parent=Main.WebHome&title=X&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -742,8 +754,6 @@ void existingDocumentNonTerminalFromUIDeprecatedCheckEscaping() throws Exception when(document.isNew()).thenReturn(false); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token425553"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI space=X.Y&tocreate=space when(mockRequest.getParameter("space")).thenReturn("X.Y"); @@ -760,7 +770,7 @@ void existingDocumentNonTerminalFromUIDeprecatedCheckEscaping() throws Exception // Note1: The space parameter was previously considered as space name, not space reference, so it is escaped. // Note2: We are creating X\.Y.WebHome because the tocreate parameter says "space". verify(mockURLFactory).createURL("X\\.Y", "WebHome", "edit", - "template=&parent=Main.WebHome&title=X.Y&form_token=" + csrfTokenValue, null, + "template=&parent=Main.WebHome&title=X.Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -901,8 +911,6 @@ void existingDocumentFromUITemplateProviderSpecified() throws Exception when(document.isNew()).thenReturn(false); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token42008766"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI spaceReference=X&name=Y&templateProvider=XWiki.MyTemplateProvider String templateProviderFullName = "XWiki.MyTemplateProvider"; @@ -924,7 +932,7 @@ void existingDocumentFromUITemplateProviderSpecified() throws Exception // Note: We are creating X.Y and using the template extracted from the template provider. verify(mockURLFactory).createURL("X.Y", "WebHome", "edit", - "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, null, "xwiki", + "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -977,8 +985,6 @@ void existingDocumentFromUITemplateProviderSpecifiedRestrictionExistsOnParentSpa when(document.isNew()).thenReturn(false); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token4221098"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI spaceReference=X.Y.Z&name=W&templateProvider=XWiki.MyTemplateProvider String templateProviderFullName = "XWiki.MyTemplateProvider"; @@ -1004,7 +1010,7 @@ void existingDocumentFromUITemplateProviderSpecifiedRestrictionExistsOnParentSpa // document // Note2: We are creating X.Y.Z.W and using the template extracted from the template provider. verify(mockURLFactory).createURL("X.Y.Z.W", "WebHome", "edit", - "template=XWiki.MyTemplate&parent=Main.WebHome&title=W&form_token=" + csrfTokenValue, + "template=XWiki.MyTemplate&parent=Main.WebHome&title=W&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -1132,8 +1138,6 @@ void newDocumentWebHomeFromURLTemplateProviderSpecifiedTerminal() throws Excepti when(document.isNew()).thenReturn(true); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token42988733"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Specifying a template provider in the URL: templateprovider=XWiki.MyTemplateProvider String templateProviderFullName = "XWiki.MyTemplateProvider"; @@ -1155,7 +1159,7 @@ void newDocumentWebHomeFromURLTemplateProviderSpecifiedTerminal() throws Excepti // Note: We are creating the document X.Y as terminal and using a template, as specified in the template // provider. verify(mockURLFactory).createURL("X", "Y", "edit", - "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, + "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -1169,8 +1173,6 @@ void newDocumentWebHomeFromURLTemplateProviderSpecifiedTerminalOverriddenFromUIT when(document.isNew()).thenReturn(true); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token4222113555"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Specifying a template provider in the URL: templateprovider=XWiki.MyTemplateProvider String templateProviderFullName = "XWiki.MyTemplateProvider"; @@ -1193,7 +1195,7 @@ void newDocumentWebHomeFromURLTemplateProviderSpecifiedTerminalOverriddenFromUIT // Note: We are creating the document X.Y.WebHome as non-terminal even if the template provider says otherwise. // Also using a template, as specified in the template provider. verify(mockURLFactory).createURL("X.Y", "WebHome", "edit", - "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, + "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -1207,8 +1209,6 @@ void newDocumentFromURLTemplateProviderSpecifiedNonTerminal() throws Exception when(document.isNew()).thenReturn(true); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token4200983331"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Specifying a template provider in the URL: templateprovider=XWiki.MyTemplateProvider String templateProviderFullName = "XWiki.MyTemplateProvider"; @@ -1230,7 +1230,7 @@ void newDocumentFromURLTemplateProviderSpecifiedNonTerminal() throws Exception // Note: We are creating the document X.Y as terminal and using a template, as specified in the template // provider. verify(mockURLFactory).createURL("X.Y", "WebHome", "edit", - "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, + "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -1244,8 +1244,6 @@ void newDocumentFromURLTemplateProviderSpecifiedNonTerminalButOverriddenFromUITe when(document.isNew()).thenReturn(true); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token42234456"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Specifying a template provider in the URL: templateprovider=XWiki.MyTemplateProvider String templateProviderFullName = "XWiki.MyTemplateProvider"; @@ -1268,7 +1266,7 @@ void newDocumentFromURLTemplateProviderSpecifiedNonTerminalButOverriddenFromUITe // Note: We are creating the document X.Y as terminal and using a template, as specified in the template // provider. verify(mockURLFactory).createURL("X", "Y", "edit", - "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, + "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -1283,8 +1281,6 @@ void existingDocumentFromUITemplateSpecified() throws Exception when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token4298833"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI spaceReference=X&name=Y&template=XWiki.MyTemplate String templateDocumentFullName = "XWiki.MyTemplate"; @@ -1307,7 +1303,7 @@ void existingDocumentFromUITemplateSpecified() throws Exception // Note: We are creating X.Y.WebHome and using the template specified in the request. verify(mockURLFactory).createURL("X.Y", "WebHome", "edit", - "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, + "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -1321,8 +1317,6 @@ void existingDocumentFromUITemplateProviderSpecifiedTerminal() throws Exception when(document.isNew()).thenReturn(false); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token4244112"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI spaceReference=X&name=Y&templateProvider=XWiki.MyTemplateProvider String templateProviderFullName = "XWiki.MyTemplateProvider"; @@ -1347,7 +1341,7 @@ void existingDocumentFromUITemplateProviderSpecifiedTerminal() throws Exception // Note: We are creating the document X.Y as terminal and using a template, as specified in the template // provider. verify(mockURLFactory).createURL("X", "Y", "edit", - "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, + "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -1361,8 +1355,6 @@ void existingDocumentFromUITemplateProviderSpecifiedTerminalOverridenFromUIToNon when(document.isNew()).thenReturn(false); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token422555987"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI spaceReference=X&name=Y&templateProvider=XWiki.MyTemplateProvider String templateProviderFullName = "XWiki.MyTemplateProvider"; @@ -1388,7 +1380,7 @@ void existingDocumentFromUITemplateProviderSpecifiedTerminalOverridenFromUIToNon // Note: We are creating the document X.Y.WebHome as non-terminal, even if the template provider says otherwise. // Also using a template, as specified in the template provider. verify(mockURLFactory).createURL("X.Y", "WebHome", "edit", - "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, + "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -1402,8 +1394,6 @@ void existingDocumentFromUITemplateProviderSpecifiedNonTerminal() throws Excepti when(document.isNew()).thenReturn(false); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token424111553"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI spaceReference=X&name=Y&templateProvider=XWiki.MyTemplateProvider String templateProviderFullName = "XWiki.MyTemplateProvider"; @@ -1428,7 +1418,7 @@ void existingDocumentFromUITemplateProviderSpecifiedNonTerminal() throws Excepti // Note: We are creating the document X.Y.WebHome as non-terminal and using a template, as specified in the // template provider. verify(mockURLFactory).createURL("X.Y", "WebHome", "edit", - "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, + "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -1442,8 +1432,6 @@ void existingDocumentFromUITemplateProviderSpecifiedNonTerminalOverridenFromUITo when(document.isNew()).thenReturn(false); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token42008733"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI spaceReference=X&name=Y&templateProvider=XWiki.MyTemplateProvider String templateProviderFullName = "XWiki.MyTemplateProvider"; @@ -1469,7 +1457,7 @@ void existingDocumentFromUITemplateProviderSpecifiedNonTerminalOverridenFromUITo // Note: We are creating the document X.Y as terminal, even if the template provider says otherwise. // Also using a template, as specified in the template provider. verify(mockURLFactory).createURL("X", "Y", "edit", - "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, + "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -1483,8 +1471,6 @@ void newDocumentWebHomeFromURLTemplateProviderSpecifiedButOldPageType() throws E when(document.isNew()).thenReturn(true); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token423366"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Specifying a template provider in the URL: templateprovider=XWiki.MyTemplateProvider String templateProviderFullName = "XWiki.MyTemplateProvider"; @@ -1507,7 +1493,7 @@ void newDocumentWebHomeFromURLTemplateProviderSpecifiedButOldPageType() throws E // property and it used the old "page" type instead. Also using a template, as specified in the template // provider. verify(mockURLFactory).createURL("X", "Y", "edit", - "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, + "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -1522,8 +1508,6 @@ void newDocumentWebHomeFromURLTemplateProviderSpecifiedButOldPageTypeButOverridd when(document.isNew()).thenReturn(true); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token4265677398"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Specifying a template provider in the URL: templateprovider=XWiki.MyTemplateProvider String templateProviderFullName = "XWiki.MyTemplateProvider"; @@ -1547,7 +1531,7 @@ void newDocumentWebHomeFromURLTemplateProviderSpecifiedButOldPageTypeButOverridd // specify a "terminal" property and it used the old "page" type, the UI explicitly asked for a non-terminal // document. Also using a template, as specified in the template provider. verify(mockURLFactory).createURL("X.Y", "WebHome", "edit", - "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, + "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -1561,8 +1545,6 @@ void existingDocumentFromUITemplateProviderSpecifiedButOldSpaceType() throws Exc when(document.isNew()).thenReturn(false); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token421198337"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI spaceReference=X&name=Y&templateProvider=XWiki.MyTemplateProvider String templateProviderFullName = "XWiki.MyTemplateProvider"; @@ -1587,7 +1569,7 @@ void existingDocumentFromUITemplateProviderSpecifiedButOldSpaceType() throws Exc // property and we fallback on the "type" property's value. Also using the template extracted from the template // provider. verify(mockURLFactory).createURL("X.Y", "WebHome", "edit", - "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, + "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); } @@ -1601,8 +1583,6 @@ void existingDocumentFromUITemplateProviderSpecifiedButOldSpaceTypeButOverridenF when(document.isNew()).thenReturn(false); when(document.getLocalReferenceMaxLength()).thenReturn(255); context.setDoc(document); - String csrfTokenValue = "token429866333"; - when(this.csrfToken.getToken()).thenReturn(csrfTokenValue); // Submit from the UI spaceReference=X&name=Y&templateProvider=XWiki.MyTemplateProvider String templateProviderFullName = "XWiki.MyTemplateProvider"; @@ -1627,7 +1607,7 @@ void existingDocumentFromUITemplateProviderSpecifiedButOldSpaceTypeButOverridenF // Note: We are creating X.Y as terminal, since it is overriden from the UI, regardless of any backwards // compatibility resolutions. Also using the template extracted from the template provider. verify(mockURLFactory).createURL("X", "Y", "edit", - "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + csrfTokenValue, + "template=XWiki.MyTemplate&parent=Main.WebHome&title=Y&form_token=" + CSRF_TOKEN_VALUE, null, "xwiki", context); }
xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-templates/src/main/resources/templates/createinline.vm+1 −0 modified@@ -276,6 +276,7 @@ ## By the past, it was "xwiki/create.js" which created this field, but it was causing problems when the user sent the ## form before the JavaScript code was executed. <input type="hidden" name="templateprovider" id="templateprovider" value="" /> + <input type="hidden" name="form_token" value="$!{escapetool.xml($services.csrf.getToken())}"/> <div class='row'> ## Hide the first column when displayed in an AJAX call by clicking on a Wanted Link (because we know the target
123e5d7e4ca0XWIKI-3945: Don't show blacklisted spaces only for simple users
1 file changed · +9 −2
xwiki-platform-web/standard/src/main/webapp/templates/xwikivars.vm+9 −2 modified@@ -8,8 +8,6 @@ #set($spaceViewUrl = $spaceDoc.getURL("view")) #set($viewUrl = $doc.getURL("view")) #set($userObj = $!crtUserDoc.getObject("XWiki.XWikiUsers",0)) -## TODO : replace this list by a hidden space feature. -#set($blacklistedSpaces = ["Import", "Panels", "Scheduler", "Stats", "XAppClasses", "XAppSheets", "XAppTemplates", "XWiki", "WatchCode", "WatchSheets", "XApp", "WatchAdmin", "Watch"]) ## ===================================================================================== ## Advanced users are: ## - super admin @@ -25,6 +23,15 @@ #else #set($isAdvancedUser = ($userObj.getProperty("usertype").value == "Advanced")) #end +## ====================================================================================== +## Compute list of spaces to blacklist so that simple users don't see them. +## TODO : replace this list by a hidden space feature. +## ====================================================================================== +#if($hasAdmin || $isAdvancedUser) + #set($blacklistedSpaces = []) +#else + #set($blacklistedSpaces = ["Import", "Panels", "Scheduler", "Stats", "XAppClasses", "XAppSheets", "XAppTemplates", "XWiki", "WatchCode", "WatchSheets", "XApp", "WatchAdmin", "Watch"]) +#end #set($parent ="<a href='$parentDoc.getURL()'>$xwiki.getXMLEncoded(${parentDoc.displayTitle})</a>") #if($tdoc) #set($headertitle = "<a href='$viewUrl'>$xwiki.getXMLEncoded(${tdoc.displayTitle})</a>")
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
6- github.com/advisories/GHSA-4f8m-7h83-9f6mghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-40572ghsaADVISORY
- github.com/xwiki/xwiki-platform/commit/123e5d7e4ca06bf75b95aaef665aafc4fa9cae64ghsaWEB
- github.com/xwiki/xwiki-platform/commit/4b20528808d0c311290b0d9ab2cfc44063380ef7ghsax_refsource_MISCWEB
- github.com/xwiki/xwiki-platform/security/advisories/GHSA-4f8m-7h83-9f6mghsax_refsource_CONFIRMWEB
- jira.xwiki.org/browse/XWIKI-20849ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.