Remote code execution in xwiki-platform
Description
XWiki Platform is a generic wiki platform offering runtime services for applications built on top of it. In affected versions it's possible for an unprivileged user to perform a remote code execution by injecting a groovy script in her own profile and by calling the Reset password feature since the feature is performing a save of the user profile with programming rights in the impacted versions of XWiki. The issue has been patched in XWiki 13.1RC1. There are two different possible workarounds, each consisting of modifying the XWiki/ResetPassword page. 1. The Reset password feature can be entirely disabled by deleting the XWiki/ResetPassword page. 2. The script in XWiki/ResetPassword can also be modified or removed: an administrator can replace it with a simple email contact to ask an administrator to reset the password.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.xwiki.platform:xwiki-platform-administration-uiMaven | >= 3.1-milestone-1, < 13.1RC1 | 13.1RC1 |
Affected products
1- Range: > 3.1M1, < 13.1RC1
Patches
1407caeba05c1XAADMINISTRATION-196: Reset Password fails in private wikis
5 files changed · +130 −141
xwiki-platform-administration/src/main/resources/XWiki/ForgotUsername.xml+27 −23 modified@@ -5,7 +5,7 @@ <language></language> <defaultLanguage>en</defaultLanguage> <translation>0</translation> -<parent>XWiki.WebHome</parent> +<parent>Main.WebHome</parent> <creator>XWiki.Admin</creator> <author>XWiki.Admin</author> <customClass></customClass> @@ -14,13 +14,13 @@ <date>1219710939000</date> <contentUpdateDate>1219710939000</contentUpdateDate> <version>1.1</version> -<title>$msg.get("xe.admin.passwordreset.forgotusername")</title> +<title>$msg.get("xe.admin.forgotUsername.title")</title> <template></template> <defaultTemplate></defaultTemplate> <validationScript></validationScript> <comment></comment> <minorEdit>false</minorEdit> -<syntaxId>xwiki/2.0</syntaxId> +<syntaxId>xwiki/2.1</syntaxId> <hidden>false</hidden> <object> <class> @@ -89,13 +89,16 @@ </users> </class> <name>XWiki.ForgotUsername</name> -<number>1</number> +<number>0</number> <className>XWiki.XWikiRights</className> -<guid>5f9081d2-87b6-430e-8bb9-edc66544fc05</guid> +<guid>5f9081d2-87b6-430e-8bb9-edc66544fc06</guid> <property> <allow>0</allow> </property> <property> +<groups>XWiki.XWikiAllGroup</groups> +</property> +<property> <levels>edit</levels> </property> <property> @@ -169,9 +172,9 @@ </users> </class> <name>XWiki.ForgotUsername</name> -<number>3</number> +<number>1</number> <className>XWiki.XWikiRights</className> -<guid>54be8bc6-c81a-4149-b2b0-161b2b974856</guid> +<guid>54be8bc6-c81a-4149-b2b0-161b2b974857</guid> <property> <allow>0</allow> </property> @@ -249,49 +252,50 @@ </users> </class> <name>XWiki.ForgotUsername</name> -<number>5</number> +<number>2</number> <className>XWiki.XWikiRights</className> -<guid>3b1dcd67-ca67-47a4-a5ab-66c26bbec642</guid> +<guid>06daec64-228b-4da1-b7e6-b59d9624c859</guid> <property> -<allow>0</allow> +<allow>1</allow> </property> <property> <groups>XWiki.XWikiAllGroup</groups> </property> <property> -<levels>edit</levels> +<levels>view</levels> +</property> +<property> +<users>XWiki.XWikiGuest</users> </property> </object> <content>{{velocity}} #set($email = "$!request.get('e')") #if($email == '') -= $msg.get('xe.admin.passwordreset.forgotusername') = - -$msg.get('xe.admin.passwordreset.enteremail') +$msg.get('xe.admin.forgotUsername.instructions') {{html}} <form method="post" action=""> - <div><label for="e">$msg.get('xe.admin.passwordreset.email')</label><input type="text" id="e" name="e"/> <span class="buttonwrapper"><input type="submit" value="$msg.get('xe.admin.passwordreset.retrieve')" class="button"/></span></div> + <div><label for="e">$msg.get('xe.admin.forgotUsername.emailLabel')</label> <input type="text" id="e" name="e"/> <span class="buttonwrapper"><input type="submit" value="$msg.get('xe.admin.forgotUsername.submit')" class="button"/></span></div> </form> {{/html}} #else - #set($results = $xwiki.searchDocuments(", BaseObject obj, StringProperty prop where obj.name = doc.fullName and obj.className = 'XWiki.XWikiUsers' and prop.id.id = obj.id and prop.id.name = 'email' and prop.value = '$escapetool.sql($email)'")) + #set($results = $xwiki.searchDocuments(", BaseObject obj, StringProperty prop where obj.name = doc.fullName and obj.className = 'XWiki.XWikiUsers' and prop.id.id = obj.id and prop.id.name = 'email' and LOWER(prop.value) = ?", [$email.toLowerCase()])) #if($results.size() == 0) - $msg.get("xe.admin.passwordreset.noaccountregistered") + $msg.get('xe.admin.forgotUsername.error.noAccount') - [[« $msg.get("xe.admin.passwordreset.differentaddress")>>$doc.fullName]] | {{html}}<a href="$xwiki.getURL('XWiki.XWikiLogin', 'login', '')">$msg.get('xe.admin.passwordreset.login') »</a>{{/html}} + [[$msg.get('xe.admin.forgotUsername.error.retry')>>$doc.fullName]] | [[$msg.get('xe.admin.forgotUsername.login')>>path:${xwiki.getURL('XWiki.XWikiLogin', 'login')}]] #elseif($results.size() == 1) - $msg.get('xe.admin.passwordreset.usernameis') **${xwiki.getDocument($results.get(0)).name}** + $msg.get('xe.admin.forgotUsername.result', ["**${results.get(0).substring($results.get(0).indexOf('.')).substring(1)}**"]) - {{html}}<a href="$xwiki.getURL('XWiki.XWikiLogin', 'login', '')">$msg.get('xe.admin.passwordreset.login') »</a>{{/html}} + [[$msg.get('xe.admin.forgotUsername.login')>>path:${xwiki.getURL('XWiki.XWikiLogin', 'login')}]] #else - $msg.get('xe.admin.passwordreset.multipleusernames') + $msg.get('xe.admin.forgotUsername.multipleResults') #foreach($item in $results) - * **${xwiki.getDocument($item).name}** + * **${item.substring($item.indexOf('.')).substring(1)}** #end - {{html}}<a href="$xwiki.getURL('XWiki.XWikiLogin', 'login', '')">$msg.get('xe.admin.passwordreset.login') »</a>{{/html}} + [[$msg.get('xe.admin.forgotUsername.login')>>path:${xwiki.getURL('XWiki.XWikiLogin', 'login')}]] #end #end {{/velocity}}</content></xwikidoc>
xwiki-platform-administration/src/main/resources/XWiki/ResetPasswordComplete.xml+55 −51 modified@@ -5,7 +5,7 @@ <language></language> <defaultLanguage>en</defaultLanguage> <translation>0</translation> -<parent>XWiki.WebHome</parent> +<parent>XWiki.ResetPassword</parent> <creator>XWiki.Admin</creator> <author>XWiki.Admin</author> <customClass></customClass> @@ -14,13 +14,13 @@ <date>1219710939000</date> <contentUpdateDate>1219710939000</contentUpdateDate> <version>1.1</version> -<title>Reset password (step 2)</title> +<title>$msg.get("xe.admin.passwordReset.step2.title")</title> <template></template> <defaultTemplate></defaultTemplate> <validationScript></validationScript> <comment></comment> <minorEdit>false</minorEdit> -<syntaxId>xwiki/2.0</syntaxId> +<syntaxId>xwiki/2.1</syntaxId> <hidden>false</hidden> <object> <class> @@ -89,18 +89,21 @@ </users> </class> <name>XWiki.ResetPasswordComplete</name> -<number>1</number> +<number>0</number> <className>XWiki.XWikiRights</className> <guid>7fd88649-d66d-442a-bcee-bc4147e410a7</guid> <property> <allow>0</allow> </property> <property> -<groups>xwiki:XWiki.XWikiAllGroup</groups> +<groups>XWiki.XWikiAllGroup</groups> </property> <property> <levels>edit</levels> </property> +<property> +<users>XWiki.XWikiGuest</users> +</property> </object> <object> <class> @@ -169,14 +172,14 @@ </users> </class> <name>XWiki.ResetPasswordComplete</name> -<number>3</number> +<number>1</number> <className>XWiki.XWikiRights</className> -<guid>e0264a66-4a10-4d7e-822e-6863e3caaa17</guid> +<guid>e0264a66-4a10-4d7e-822e-6863e3caaa18</guid> <property> <allow>0</allow> </property> <property> -<groups>XWiki.XWikiAllGroup</groups> +<groups>xwiki:XWiki.XWikiAllGroup</groups> </property> <property> <levels>edit</levels> @@ -249,14 +252,17 @@ </users> </class> <name>XWiki.ResetPasswordComplete</name> -<number>5</number> +<number>2</number> <className>XWiki.XWikiRights</className> -<guid>bb790edf-7dcc-4646-9cf9-855b439cef7f</guid> +<guid>06daec64-228b-4da1-b7e6-b59d9624c856</guid> <property> -<allow>0</allow> +<allow>1</allow> </property> <property> -<levels>edit</levels> +<groups>XWiki.XWikiAllGroup</groups> +</property> +<property> +<levels>view</levels> </property> <property> <users>XWiki.XWikiGuest</users> @@ -286,7 +292,7 @@ it is secured against unprivileged editing. ## ## ## The name of the class used for storing password reset verification data. -#set($verifClass = 'XWiki.ResetPasswordRequestClass') +#set ($verifClass = 'XWiki.ResetPasswordRequestClass') ## ## START MACROS ## @@ -298,7 +304,7 @@ it is secured against unprivileged editing. * @param result The encrypted output. *# #macro(encrypt $value $result) - #set($result = $xwiki.getDocument($verifClass).getxWikiClass().getXWikiClass().get('verification').getPasswordHash($value)) + #set ($result = $xwiki.getDocument($verifClass).getxWikiClass().getXWikiClass().get('verification').getPasswordHash($value)) #end ## ## @@ -308,12 +314,13 @@ it is secured against unprivileged editing. * @param validationString The unencrypted key that is stored in the ResetPasswordRequestClass object. * @param result A boolean where the validation result is returned. True if the request is valid, false otherwise. *# -#macro(verifyRequest $userName $validationString $result) - #set($result = false) - #if($validationString != '' && $userName != '') - #encrypt($validationString $encryptedValidationString) - #if("$!xwiki.getDocument($userName).getObject($verifClass).getProperty('verification').getValue()" == $encryptedValidationString) - #set($result = true) +#macro(verifyRequest $userName $validationString $isValid) + #set ($isValid = false) + #if ($validationString != '' && $userName != '') + #encrypt($validationString $result) + #set ($encryptedValidationString = $result) + #if ("$!xwiki.getDocument($userName).getObject($verifClass).getProperty('verification').getValue()" == $encryptedValidationString) + #set ($isValid = true) #end #end #end @@ -326,87 +333,84 @@ it is secured against unprivileged editing. * @param v The validation string, which will be checked again upon receiving the form. *### #macro(displayForm $message $userName $validationString) - = $msg.get('xe.admin.passwordreset.resetfor', [${xwiki.getUserName($userName, false)}]) = - #if($message != '') - + #if ($message != '') {{warning}}$message{{/warning}} #end {{html}} - <form action="$doc.getURL()" method="post" onsubmit="if($('p').value == '') {alert('$msg.get("xe.admin.passwordreset.emptystring")'); return false;} else if($('p').value != $('p2').value) {alert('$msg.get("xe.admin.passwordreset.nomatch")'); return false; }"> + <form action="$doc.getURL()" method="post" class="xform third" onsubmit="if($('p').value == '') {alert('$msg.get('xe.admin.passwordReset.step2.error.emptyPassword')'); return false;} else if($('p').value != $('p2').value) {alert('$msg.get('xe.admin.passwordReset.step2.error.verificationMismatch')'); return false; }"> <div class="hidden"> <input type="hidden" name="form_token" value="$!{services.csrf.getToken()}" /> <input type="hidden" name="u" value="$!escapetool.xml($userName)"/> <input type="hidden" name="v" value="$!escapetool.xml($validationString)"/> </div> <dl> - <dt><label for="p">$msg.get('xe.admin.passwordreset.newpassword')</label></dt> + <dt><label for="p">$msg.get('xe.admin.passwordReset.step2.newPassword.label')</label></dt> <dd><input id="p" type="password" name="p" value="" size="20"/></dd> - <dt><label for="p2">$msg.get('xe.admin.passwordreset.reenterpassword')</label></dt> + <dt><label for="p2">$msg.get('xe.admin.passwordReset.step2.newPasswordVerification.label')</label></dt> <dd><input id="p2" type="password" value="" name="p2" size="20"/></dd> </dl> - <div> - <span class="buttonwrapper"><input type="submit" value="$msg.get('xe.admin.passwordreset.save')" class="button"/></span> + <div class="buttons"> + <span class="buttonwrapper"><input type="submit" value="$msg.get('xe.admin.passwordReset.step2.submit')" class="button"/></span> </div> </form> {{/html}} #end ## ## END MACROS -## ## -#set($userName = "$!request.u") -#set($validationString = "$!request.v") -#set($password = "$!request.p") -#set($password2 = "$!request.p2") -#verifyRequest($userName $validationString $result) +## +#set ($userName = "$!request.u") +#set ($validationString = "$!request.v") +#set ($password = "$!request.p") +#set ($password2 = "$!request.p2") +#verifyRequest($userName $validationString $isValid) {{/velocity}} {{velocity}} ## ## ## First, check if the page has programming rights, as nothing works otherwise -#if($xwiki.hasProgrammingRights()) -#if($result) - #set($vuserDoc = $xwiki.getDocument($userName)) - #if($request.getParameterMap().containsKey('p'))## Second step, set the user password +#if ($xwiki.hasProgrammingRights()) +#if ($isValid) + #set ($vuserDoc = $xwiki.getDocumentAsAuthor($userName)) + #if ($request.getParameterMap().containsKey('p'))## Second step, set the user password #if($password == '') - #displayForm($msg.get('xe.admin.passwordreset.notempty') $userName $validationString) + #displayForm($msg.get('xe.admin.passwordReset.step2.error.emptyPassword') $userName $validationString) #elseif($password != $password2) - #displayForm($msg.get('xe.admin.passwordreset.nomatch') $userName $validationString) + #displayForm($msg.get('xe.admin.passwordReset.step2.error.verificationMismatch') $userName $validationString) #else $vuserDoc.getObject('XWiki.XWikiUsers').set('password', $password) #set($discard = $vuserDoc.removeObjects($verifClass)) - $vuserDoc.saveWithProgrammingRights() -{{info}}$msg.get('xe.admin.passwordreset.success') {{html}}<a href='$xwiki.getURL('XWiki.XWikiLogin', 'login')'>$msg.get('xe.admin.passwordreset.loginsmall')</a>{{/html}} $msg.get('xe.admin.passwordreset.successend'){{/info}} + #set ($discard = $vuserDoc.saveAsAuthor($msg.get('xe.admin.passwordReset.step2.versionComment.passwordReset'), true)) +{{info}}$msg.get('xe.admin.passwordReset.step2.success') [[$msg.get('xe.admin.passwordReset.step2.login')>>path:$xwiki.getURL('XWiki.XWikiLogin', 'login')]]{{/info}} #end #else## First step, request the user password ## The user might not complete this step, and leave the URL in the (public) browser's ## history. Prevent reusing the URL by invalidating the initial verification URL and only ## post the new string in the hidden form data. - #set($validationString = $util.generateRandomString(30)) - $vuserDoc.getObject($verifClass).set('verification', $validationString) - $vuserDoc.saveWithProgrammingRights() + #set ($validationString = $util.generateRandomString(30)) + #set ($discard = $vuserDoc.getObject($verifClass).set('verification', $validationString)) + #set ($discard = $vuserDoc.saveAsAuthor($msg.get('xe.admin.passwordReset.step2.versionComment.changeValidationKey'), true)) #displayForm('' $userName $validationString) #end #else - #set($backToResetLink = " [[$msg.get('xe.admin.passwordreset.backtoreset') »>>ResetPassword]]") -{{error}}$msg.get('xe.admin.passwordreset.wrongparameters') ${backToResetLink}{{/error}} +{{error}}$msg.get('xe.admin.passwordReset.step2.error.wrongParameters') [[$msg.get('xe.admin.passwordReset.step2.backToStep1')>>ResetPassword]]{{/error}} #end ## ## Clear private variables, so that they cannot be accessed from the rest of the page (comments, panels...) -#set($validationString = '') -#set($password = '') -#set($password2 = '') +#set ($validationString = '') +#set ($password = '') +#set ($password2 = '') ## ## #else## No programming rights, warn and exit -{{error}}$msg.get('xe.admin.passwordreset.noprogrammingrights'){{/error}} +{{error}}$msg.get('xe.admin.passwordReset.step2.error.noProgrammingRights'){{/error}} #end {{/velocity}}</content></xwikidoc>
xwiki-platform-administration/src/main/resources/XWiki/ResetPasswordMailContent.xml+1 −1 modified@@ -5,7 +5,7 @@ <language></language> <defaultLanguage></defaultLanguage> <translation>0</translation> -<parent>XWiki.WebHome</parent> +<parent>XWiki.ResetPassword</parent> <creator>XWiki.Admin</creator> <author>XWiki.Admin</author> <customClass></customClass>
xwiki-platform-administration/src/main/resources/XWiki/ResetPasswordRequestClass.xml+1 −1 modified@@ -5,7 +5,7 @@ <language></language> <defaultLanguage></defaultLanguage> <translation>0</translation> -<parent>XWiki.WebHome</parent> +<parent>XWiki.ResetPassword</parent> <creator>XWiki.Admin</creator> <author>XWiki.Admin</author> <customClass></customClass>
xwiki-platform-administration/src/main/resources/XWiki/ResetPassword.xml+46 −65 modified@@ -5,7 +5,7 @@ <language></language> <defaultLanguage>en</defaultLanguage> <translation>0</translation> -<parent>XWiki.WebHome</parent> +<parent>Main.WebHome</parent> <creator>XWiki.Admin</creator> <author>XWiki.Admin</author> <customClass></customClass> @@ -14,13 +14,13 @@ <date>1228221475000</date> <contentUpdateDate>1228221475000</contentUpdateDate> <version>1.1</version> -<title>$msg.get("xe.admin.passwordreset.forgotpassword")</title> +<title>$msg.get("xe.admin.passwordReset.title")</title> <template></template> <defaultTemplate></defaultTemplate> <validationScript></validationScript> <comment></comment> <minorEdit>false</minorEdit> -<syntaxId>xwiki/2.0</syntaxId> +<syntaxId>xwiki/2.1</syntaxId> <hidden>false</hidden> <object> <class> @@ -101,6 +101,9 @@ <property> <levels>edit</levels> </property> +<property> +<users>XWiki.XWikiGuest</users> +</property> </object> <object> <class> @@ -171,15 +174,15 @@ <name>XWiki.ResetPassword</name> <number>1</number> <className>XWiki.XWikiRights</className> -<guid>8e791339-668e-4a3c-9d44-a28396c1d66f</guid> +<guid>bb00007c-00dd-4423-9b7b-b87896c947fb</guid> <property> <allow>0</allow> </property> <property> -<levels>edit</levels> +<groups>xwiki:XWiki.XWikiAllGroup</groups> </property> <property> -<users>XWiki.XWikiGuest</users> +<levels>edit</levels> </property> </object> <object> @@ -251,15 +254,18 @@ <name>XWiki.ResetPassword</name> <number>2</number> <className>XWiki.XWikiRights</className> -<guid>bb00007c-00dd-4423-9b7b-b87896c947fb</guid> +<guid>06daec64-228b-4da1-b7e6-b59d9624c866</guid> <property> -<allow>0</allow> +<allow>1</allow> </property> <property> -<groups>xwiki:XWiki.XWikiAllGroup</groups> +<groups>XWiki.XWikiAllGroup</groups> </property> <property> -<levels>edit</levels> +<levels>view</levels> +</property> +<property> +<users>XWiki.XWikiGuest</users> </property> </object> <content>{{velocity}} @@ -272,99 +278,74 @@ This page starts the password reset procedure. It works according to the next al URL parameters: u = user account sent in the form - -!!!!! IMPORTANT !!!!! - -This document requires programming rights, so always make sure -it is saved by a user with programming rights, and that -it is secured against unprivileged editing. - *### ## ## -## First, check if the page has programming rights, as nothing works otherwise -#if($xwiki.hasProgrammingRights()) -## -## ## The name of the class used for storing password reset verification data. -#set($verifClass = 'XWiki.ResetPasswordRequestClass') -#set($userName = "$!request.get('u')") -#if($userName == '')## First step, display the form requesting the username - = $msg.get('xe.admin.passwordreset.forgotpassword') = - - $msg.get('xe.admin.passwordreset.startprocess') +#set ($verifClass = 'XWiki.ResetPasswordRequestClass') +#set ($userName = "$!request.get('u')") +#if ($userName == '')## First step, display the form requesting the username + $msg.get('xe.admin.passwordReset.instructions') {{html}} - <form method="post" action=""> + <form method="post" action="" class="xformInline"> <div> <input type="hidden" name="form_token" value="$!{services.csrf.getToken()}" /> - <label for="u">$msg.get('xe.admin.passwordreset.username')</label> <input type="text" id="u" name="u"/> <span class="buttonwrapper"><input type="submit" value="$msg.get('xe.admin.passwordreset.resetpassword')" class="button"/></span> + <label for="u">$msg.get('xe.admin.passwordReset.username.label')</label> <input type="text" id="u" name="u"/> <span class="buttonwrapper"><input type="submit" value="$msg.get('xe.admin.passwordReset.submit')" class="button"/></span> </div> </form> {{/html}} #else## Second step, generate the verification string, store it, and send the email ## TODO: Once the usernames are not bound to the XWiki space, revisit this code - #if($userName.indexOf('.') != -1) - #set($userDoc = $xwiki.getDocument(${userName})) + #if ($userName.indexOf('.') != -1) + #set ($userDoc = $xwiki.getDocumentAsAuthor(${userName})) #else - #set($userDoc = $xwiki.getDocument("XWiki.${userName}")) + #set ($userDoc = $xwiki.getDocumentAsAuthor("XWiki.${userName}")) #end ## Check if the user exists and has a valid email address configured in his profile - #set($userObj = '') - #set($userObj = $userDoc.getObject('XWiki.XWikiUsers')) - #if("$!userObj" == '') + #set ($userObj = '') + #set ($userObj = $userDoc.getObject('XWiki.XWikiUsers')) + #if (!$userObj) - {{warning}}$msg.get('xe.admin.passwordreset.nouser', [$escapetool.xml($userName)]){{/warning}} + {{warning}}$msg.get('xe.admin.passwordReset.error.noUser', ["//${escapetool.xml($userName)}//"]){{/warning}} #elseif ($userDoc.getObject('XWiki.LDAPProfileClass')) - {{warning}}$msg.get('xe.admin.passwordreset.ldapuser', [$escapetool.xml($userName)]){{/warning}} + {{warning}}$msg.get('xe.admin.passwordReset.error.ldapUser', ["//${escapetool.xml($userName)}//"]){{/warning}} #else - #set($userEmail = $userObj.getProperty('email').value) - #if("$!userEmail" == '') + #set ($userEmail = $userObj.getProperty('email').value) + #if ("$!userEmail" == '') - {{error}}$msg.get('xe.admin.passwordreset.cannotreset'){{/error}} + {{error}}$msg.get('xe.admin.passwordReset.error.noEmail'){{/error}} #else ## Find the object that will hold the verification string - #set($verifObj = '') - #set($verifObj = $userDoc.getObject($verifClass)) - #if("$!verifObj" == '') - #set($verifObj = $userDoc.newObject($verifClass)) - #end + #set ($verifObj = '') + #set ($verifObj = $userDoc.getObject($verifClass, true)) ## Generate a random string - #set($verifStr = $xwiki.generateRandomString(30)) + #set ($verifStr = $xwiki.generateRandomString(30)) ## If the class is correctly configured, the string should automatically be stored as a hash - #set($discard = $verifObj.set('verification', $verifStr)) - #set($discard = $userDoc.saveWithProgrammingRights()) + #set ($discard = $verifObj.set('verification', $verifStr)) + #set ($discard = $userDoc.saveAsAuthor($msg.get('xe.admin.passwordReset.versionComment'), true)) ## Compose the verification URL - #set($passwordResetURL = $xwiki.getDocument('XWiki.ResetPasswordComplete').getExternalURL('view', "u=${userName}&amp;v=${verifStr}")) + #set ($passwordResetURL = $xwiki.getDocument('XWiki.ResetPasswordComplete').getExternalURL('view', "u=${userName}&amp;v=${verifStr}")) ## Send an email; the variables will be retrieved from the velocity context - #set($mailResult = $xwiki.mailsender.sendMessageFromTemplate($xwiki.getXWikiPreference('admin_email', 'no-reply@xwiki.org'), $userEmail, $util.null, $util.null, $xcontext.language, 'XWiki.ResetPasswordMailContent', $xcontext.vcontext)) - #if($mailResult == 0) + #set ($mailResult = $xwiki.mailsender.sendMessageFromTemplate($xwiki.getXWikiPreference('admin_email', 'no-reply@xwiki.org'), $userEmail, $util.null, $util.null, $xcontext.language, 'XWiki.ResetPasswordMailContent', $util.null)) + #if ($mailResult == 0) - {{info}}$msg.get('xe.admin.passwordreset.emailsent', [$escapetool.xml($userEmail)]){{/info}} + {{info}}$msg.get('xe.admin.passwordReset.emailSent', ["${escapetool.h}#${escapetool.xml($userEmail)}${escapetool.h}#"]){{/info}} #else - {{error}}$msg.get('xe.admin.passwordreset.reseterror'){{/error}} + {{error}}$msg.get('xe.admin.passwordReset.error.emailFailed'){{/error}} #end #end #end - {{html}} - <a href="$doc.getURL()">« $msg.get('xe.admin.passwordreset.retry')</a> | - <a href="$xwiki.getURL('XWiki.XWikiLogin', 'login', '')">$msg.get('xe.admin.passwordreset.login') »</a> - {{/html}} + [[$msg.get('xe.admin.passwordReset.error.retry')>>$doc.fullName]] | [[$msg.get('xe.admin.passwordReset.error.recoverUsername')>>ForgotUsername]] | [[$msg.get('xe.admin.passwordReset.login')>>path:$xwiki.getURL('XWiki.XWikiLogin', 'login')]] #end ## Clear private variables, so that they cannot be accessed from the rest of the page (comments, panels...) -#set($verifStr = '') -#set($passwordResetURL = '') -## -## -#else - ## No programming rights, warn and exit - {{error}}$msg.get('xe.admin.passwordreset.noprogrammingrights'){{/error}} -#end +#set ($verifStr = '') +#set ($passwordResetURL = '') {{/velocity}}</content></xwikidoc>
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- github.com/advisories/GHSA-mgjw-2wrp-r535ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2022-23616ghsaADVISORY
- github.com/xwiki/xwiki-platform/commit/407caeba05c181bd4835e1dd12e431fa15ff728bghsaWEB
- github.com/xwiki/xwiki-platform/security/advisories/GHSA-mgjw-2wrp-r535ghsax_refsource_CONFIRMWEB
- jira.xwiki.org/browse/XWIKI-16661ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.