CVE-2023-45144: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: com.xwiki.identity-oauth:identity-oauth-ui is a package to aid in building identity and service providers based on OAuth authorizations. When a user logs in via the OAuth method, the identityOAuth parameters sent in the GET request is vulnerable to cross site scripting (XSS) and XWiki syntax injection. This allows remote code execution via the groovy macro and thus affects the confidentiality, integrity and availability of the whole XWiki installation. The issue has been fixed in Identity OAuth version 1.6. There are no known workarounds for this vulnerability and users are advised to upgrade.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVSS v3 base score: 9.6
Published: 2023-10-16T21:15Z
Repository: https://github.com/xwikisas/identity-oauth
Language: Other
Files changed: ui/src/main/resources/IdentityOAuth/IdentityOAuthConfigMacros.vm, ui/src/main/resources/IdentityOAuth/LoginUIExtension.vm, ui/src/main/resources/IdentityOAuth/Translations.de.properties, ui/src/main/resources/IdentityOAuth/Translations.fr.properties, ui/src/main/resources/IdentityOAuth/Translations.properties, ui/src/main/resources/IdentityOAuth/WebHome.xml
Commit date: 2023-04-26 16:17:35 +0300
Commit message: Improve escaping (#30)

* remove unnecessary empty lines that where displayed when the macro was called
* don't escape links in translations; let the code using the translation to do the right link wrapping after escaping
* refactor some translation macros
* update translations that are used as fallback values in order to use the best practice for having links in translation
Diff: diff --git a/ui/src/main/resources/IdentityOAuth/IdentityOAuthConfigMacros.vm b/ui/src/main/resources/IdentityOAuth/IdentityOAuthConfigMacros.vm
index 222a6a8..cdd27e2 100644
--- a/ui/src/main/resources/IdentityOAuth/IdentityOAuthConfigMacros.vm
+++ b/ui/src/main/resources/IdentityOAuth/IdentityOAuthConfigMacros.vm
@@ -19,46 +19,57 @@
 
   ## defines formId, propNamePrefixIO, propNamePrefixO, configDoc, objIO, objO
   #macro (initConfigObjects $configDocName $extraObjectClassPropPrefixes $translationPrefixesP)
     #set($formId = "${section.toLowerCase()}_${configDocName1}")
     #set($configDoc = $xwiki.getDocument($configDocName))
-
     #set($classNameIO="IdentityOAuth.IdentityOAuthConfigClass")
     #set($propNamePrefixIO="${configDoc.fullName}_${classNameIO}_0")
     #set($objIO = $configDoc.getObject($classNameIO))
-
+    ## Handle translation prefixes.
     #set($translationPrefixes = [])
     #foreach($p in $translationPrefixesP)
       #set($nuts=$translationPrefixes.add($p))
     #end
     #set($nuts=$translationPrefixes.add('IdentityOAuth.IdentityOAuthConfigClass_'))
-
+    ## Handle extra class properties.
     #foreach($x in $extraObjectClassPropPrefixes)
       #set($shhh = $x.add($x[0]))
       #set($x[0] = $configDoc.getObject($x[0]))
     #end
   #end
 
-
-  ## t: shorthand for translation
+  ##
+  ## Macros used in managing providers translations. t is for translation and tp for translation with parameters.
+  ##
   #macro (alignWithTranslationPrefixes $name)
     #set($tn = [])
     #foreach($p in $translationPrefixes)
       #set($nuts=$tn.add("${p}${name}"))
     #end
   #end
-  #macro (t $name)
+  #macro (getTranslation $name $usage $translation)
     #alignWithTranslationPrefixes($name)
-    $services.localization.render($tn)
+    #if ($usage == 'js')
+      #set ($translation = $escapetool.javascript($services.localization.render($tn)))
+    #else
+      #set ($translation = $escapetool.xml($services.localization.render($tn)))
+    #end
   #end
-
-  ## tp: shorthand for translation with parameters
-  #macro (tp $name $params)##
+  ## Display translation.
+  #macro (t $name $usage)
+    #getTranslation($name $usage $translation)
+    $translation
+  #end
+  ## Get translation with parameters.
+  #macro (tp $name $params $usage $translation)
     #alignWithTranslationPrefixes($name)
-    #set ($msg = $services.localization.render($tn,$params))##
-    ## convert to <a href="link">link-text</a> for the simple wiki syntax of links
-    $stringtool.replacePattern($msg, '\[\[([^>]*)>>([^\]]*)\]\]', '<a href="$2">$1</a>')##
+    #set ($msg = $services.localization.render($tn, $params))##
+    #if ($usage == 'js')
+      #set ($translation = $escapetool.javascript($msg))
+    #else
+      #set ($translation = $escapetool.xml($msg))
+    #end
   #end
 
   ## displayInput: displays the form element of the relevant property of the object having removed the
   ##   html macro around it.
   #macro (displayInput $property $obj)
@@ -91,11 +102,12 @@
       #elseif($serverReturn.startsWith('/'))
         #set($absUrl = $xcontext.request.requestURL)
       // absUrl: $absUrl
         #set($serverReturn = "${absUrl.substring(0, $absUrl.indexOf('/',8))}${serverReturn}")
       #end
-      window.placeHolderForRedirectUrl = '#tp("redirectUrl.placeHolderMessage", ["${serverReturn}"])';
+      #tp("redirectUrl.placeHolderMessage", ["${serverReturn}"], "js", $translation)
+      window.placeHolderForRedirectUrl = "${translation}";
       var p = window.location.href.indexOf('/admin');
       window.browserReturnUrl = (p === -1 ?
               window.location.href :
               window.location.href.substring(0, p)) + "/login/XWiki/XWikiLogin"
   </script>
diff --git a/ui/src/main/resources/IdentityOAuth/LoginUIExtension.vm b/ui/src/main/resources/IdentityOAuth/LoginUIExtension.vm
index c2a1594..32e2712 100644
--- a/ui/src/main/resources/IdentityOAuth/LoginUIExtension.vm
+++ b/ui/src/main/resources/IdentityOAuth/LoginUIExtension.vm
@@ -27,11 +27,11 @@
         #set($email = $result.substring($prfx.length()))
         #set($errorMsg = " ${services.localization.render('idoauth.login.domainerror1')} ")
         #set($errorMsg = " ${errorMsg} ${services.localization.render('idoauth.login.domainerror2')} $!{email}.")
         #set($errorMsg = " ${errorMsg} ${services.localization.render('idoauth.login.domainerror3')}")
       #elseif ($result=="ok")
-        #set($successM = ${services.localization.render("idoauth.login.redirectmessage")})
+        #set ($successMsg = ${services.localization.render("idoauth.login.redirectmessage")})
         ## the browser should have been redirected by processOAuthReturn
       #else ## $result is "no user"
         #set($errorMsg = ${services.localization.render('idoauth.login.message')})
         #set($errorMsg = " ${errorMsg} ${services.localization.render('idoauth.login.error')}")
         #if($request.getAttribute("idoauth-error-message"))
@@ -53,11 +53,11 @@
         #else
           #set($errorMsg = $services.localization.render("idoauth.login.oauth.failedOAuth"))
         #end
       #end
     #elseif ($request.identityOAuth)
-      #set($statusMsg = "no such identityOAuth operation '$request.identityOAuth'")
+      #set ($statusMsg = "no such identityOAuth operation '$request.identityOAuth'")
     #else
       #set($statusMsg = "Login page")
       ## assemble the login code from the providers
       #set($loginCodes = '<div id="idoauth-login-choice">
                              <div class="col-xs-12">')
@@ -88,11 +88,11 @@
 
     #idoauth-login-choice {
       margin-bottom: 5%;
     }
     </style>
-    <!-- ======= ${statusMsg} ====== -->
+    <!-- ======= ${escapetool.xml($statusMsg)} ====== -->
 
     #if ($successMsg || $errorMsg)
     <script type="text/javascript">
       // Identity OAuth Login Extension: Success or warning messages
       document.addEventListener('DOMContentLoaded', function() {
diff --git a/ui/src/main/resources/IdentityOAuth/Translations.de.properties b/ui/src/main/resources/IdentityOAuth/Translations.de.properties
index 9b6c57f..0a7ad8b 100644
--- a/ui/src/main/resources/IdentityOAuth/Translations.de.properties
+++ b/ui/src/main/resources/IdentityOAuth/Translations.de.properties
@@ -4,12 +4,14 @@ idoauth.config.heading=Einstellungen des OAuth Providers
 IdentityOAuth.IdentityOAuthConfigClass_config.explanation=XWiki kann mit externen Identitätsanbietern verbunden werdeb.
 
 ## Adminstration interface
 IdentityOAuth.IdentityOAuthConfigClass_active=Aktivieren
 IdentityOAuth.IdentityOAuthConfigClass_communicate=Schnittstellen zu dem OAuth Provider
-IdentityOAuth.IdentityOAuthConfigClass_communicate.hint=Um eine OAuth Integration zu aktivieren, musst du {0}dein Wiki als App für den OAuth Zugang bei dem Provider registrieren{1} und die genannten Client-ID und Clientschlüssel in den folgenden Einstellungen einfügen.
-IdentityOAuth.IdentityOAuthConfigClass_communicate.hint2=Du erhälst mehr Information in den {0}Installationsanweisungen{1}.
+IdentityOAuth.IdentityOAuthConfigClass_communicate.hint=Um eine OAuth Integration zu aktivieren, musst du {0} und die genannten Client-ID und Clientschlüssel in den folgenden Einstellungen einfügen.
+IdentityOAuth.IdentityOAuthConfigClass_communicate.hint.linkLabel=dein Wiki als App für den OAuth Zugang bei dem Provider registrieren
+IdentityOAuth.IdentityOAuthConfigClass_communicate.hint2=Du erhälst mehr Information in den {0}.
+IdentityOAuth.IdentityOAuthConfigClass_communicate.hint2.linkLabel=Installationsanweisungen
 
 IdentityOAuth.IdentityOAuthConfigClass_appname=Name
 IdentityOAuth.IdentityOAuthConfigClass_appname.hint=Für deine eigene Organisation
 IdentityOAuth.IdentityOAuthConfigClass_clientid=Client-ID
 IdentityOAuth.IdentityOAuthConfigClass_clientid.hint=Wird vom Provider genannt.
diff --git a/ui/src/main/resources/IdentityOAuth/Translations.fr.properties b/ui/src/main/resources/IdentityOAuth/Translations.fr.properties
index 08da550..e980336 100644
--- a/ui/src/main/resources/IdentityOAuth/Translations.fr.properties
+++ b/ui/src/main/resources/IdentityOAuth/Translations.fr.properties
@@ -4,12 +4,14 @@ idoauth.config.heading=Configuration Intégration OAuth
 IdentityOAuth.IdentityOAuthConfigClass_config.explanation=XWiki peut être intégré avec un fournisseur externe d'identité.
 
 ## Adminstration interface
 IdentityOAuth.IdentityOAuthConfigClass_active=Activer
 IdentityOAuth.IdentityOAuthConfigClass_communicate=Communication avec les services OAuth
-IdentityOAuth.IdentityOAuthConfigClass_communicate.hint=Afin d''activer l''intégration OAuth vous devez vous enregistrer pour l''accès à OAuth chez le fournisseur et insérer les informations dans les paramètres suivants.
-IdentityOAuth.IdentityOAuthConfigClass_communicate.hint2=Voir aussi {0}les instructions d''installation{1}.
+IdentityOAuth.IdentityOAuthConfigClass_communicate.hint=Afin d''activer l''intégration OAuth vous devez {0} et insérer les informations dans les paramètres suivants.
+IdentityOAuth.IdentityOAuthConfigClass_communicate.hint.linkLabel=vous enregistrer pour l''accès à OAuth chez le fournisseur
+IdentityOAuth.IdentityOAuthConfigClass_communicate.hint2=Voir aussi {0}.
+IdentityOAuth.IdentityOAuthConfigClass_communicate.hint2.linkLabel=les instructions d''installation
 
 IdentityOAuth.IdentityOAuthConfigClass_appname=Nom de l'application
 IdentityOAuth.IdentityOAuthConfigClass_appname.hint=Pour votre propre organisation.
 IdentityOAuth.IdentityOAuthConfigClass_clientid=ID client
 IdentityOAuth.IdentityOAuthConfigClass_clientid.hint=Indiqué dans la page de l'application.
diff --git a/ui/src/main/resources/IdentityOAuth/Translations.properties b/ui/src/main/resources/IdentityOAuth/Translations.properties
index 38743eb..b228eef 100644
--- a/ui/src/main/resources/IdentityOAuth/Translations.properties
+++ b/ui/src/main/resources/IdentityOAuth/Translations.properties
@@ -8,12 +8,14 @@ idoauth.config.heading=Identity OAuth Integration Configuration
 IdentityOAuth.IdentityOAuthConfigClass_config.explanation=XWiki can be integrated with an external provider.
 
 ## Adminstration interface
 IdentityOAuth.IdentityOAuthConfigClass_active=Activate
 IdentityOAuth.IdentityOAuthConfigClass_communicate=Communication with the OAuth service
-IdentityOAuth.IdentityOAuthConfigClass_communicate.hint=To activate an OAuth integration you need to {0}register for OAuth access to the provider''s configuration{1} and to insert your Client-Id and secret in the following settings.
-IdentityOAuth.IdentityOAuthConfigClass_communicate.hint2=For more information, please see {0}the installation instructions{1}.
+IdentityOAuth.IdentityOAuthConfigClass_communicate.hint=To activate an OAuth integration you need to {0} and to insert your Client-Id and secret in the following settings.
+IdentityOAuth.IdentityOAuthConfigClass_communicate.hint.linkLabel=register for OAuth access to the provider''s configuration
+IdentityOAuth.IdentityOAuthConfigClass_communicate.hint2=For more information, please see {0}.
+IdentityOAuth.IdentityOAuthConfigClass_communicate.hint2.linkLabel=the installation instructions
 
 IdentityOAuth.IdentityOAuthConfigClass_appname=Application Name
 IdentityOAuth.IdentityOAuthConfigClass_appname.hint=For your own organisation.
 IdentityOAuth.IdentityOAuthConfigClass_clientid=Client ID
 IdentityOAuth.IdentityOAuthConfigClass_clientid.hint=The provider indicates this.
@@ -68,10 +70,10 @@ idoauth.login.oauth.success=Successful authentication.
 idoauth.login.oauth.successwithredirect=Successful authentication. You are being redirected to your page.
 
 idoauth.error.noValidLicense=A license for this application is missing. Please visit the License setting (in the Extensions section) to obtain one.
 idoauth.error.extensionDisabled=The IdentityOAuth integration is disabled on this wiki.
 
-idoauth.webHome.1=This is the code for the Identity OAuth extension, allowing to integrate XWiki with external provider's identities.
+idoauth.webHome.1=This is the code for the Identity OAuth extension, allowing to integrate XWiki with external provider identities.
 idoauth.webHome.2=...
 idoauth.webHome.3=...
-idoauth.webHome.4=Go to Provider's section of the XWiki Preferences in order to configure the application.
+idoauth.webHome.4=Go to the administration section of your specific provider in order to configure the application. 
 
diff --git a/ui/src/main/resources/IdentityOAuth/WebHome.xml b/ui/src/main/resources/IdentityOAuth/WebHome.xml
index 7ffcfed..9dc9492 100644
--- a/ui/src/main/resources/IdentityOAuth/WebHome.xml
+++ b/ui/src/main/resources/IdentityOAuth/WebHome.xml
@@ -44,17 +44,17 @@
 {{velocity}}
 #set ($mainReference = $services.model.createDocumentReference('', 'IdentityOAuth','OAuth'))
 #if (!$services.licensing.licensor.hasLicensureForEntity($mainReference))
   {{error}}#getMissingLicenseMessage('idoauth.extension.name'){{/error}}
 #else
-	$services.localization.render('idoauth.webHome.1')
-	$services.localization.render('idoauth.webHome.2')
-	$services.localization.render('idoauth.webHome.3')
-  $services.localization.render('idoauth.webHome.4')
+  $escapetool.xml($services.localization.render('idoauth.webHome.1'))
+  $escapetool.xml($services.localization.render('idoauth.webHome.2'))
+  $escapetool.xml($services.localization.render('idoauth.webHome.3'))
+  $escapetool.xml($services.localization.render('idoauth.webHome.4'))
 #end
 
-[[=&gt; More about the IdentityOAuth Application>>https://store.xwiki.com/xwiki/bin/view/Extension/IdentityOAuth]].
+[[=&gt; More about the IdentityOAuth Application&gt;&gt;https://store.xwiki.com/xwiki/bin/view/Extension/IdentityOAuth]].
 {{/velocity}}
 </content>
   <attachment>
     <filename>xwiki-logo.png</filename>
     <mimetype>image/png</mimetype>

Vulnerable code: 



  ## t: shorthand for translation
  #macro (t $name)
    $services.localization.render($tn)

  ## tp: shorthand for translation with parameters
  #macro (tp $name $params)##
    #set ($msg = $services.localization.render($tn,$params))##
    ## convert to <a href="link">link-text</a> for the simple wiki syntax of links
    $stringtool.replacePattern($msg, '\[\[([^>]*)>>([^\]]*)\]\]', '<a href="$2">$1</a>')##
      window.placeHolderForRedirectUrl = '#tp("redirectUrl.placeHolderMessage", ["${serverReturn}"])';
        #set($successM = ${services.localization.render("idoauth.login.redirectmessage")})
      #set($statusMsg = "no such identityOAuth operation '$request.identityOAuth'")
    <!-- ======= ${statusMsg} ====== -->
IdentityOAuth.IdentityOAuthConfigClass_communicate.hint=Um eine OAuth Integration zu aktivieren, musst du {0}dein Wiki als App für den OAuth Zugang bei dem Provider registrieren{1} und die genannten Client-ID und Clientschlüssel in den folgenden Einstellungen einfügen.
IdentityOAuth.IdentityOAuthConfigClass_communicate.hint2=Du erhälst mehr Information in den {0}Installationsanweisungen{1}.
IdentityOAuth.IdentityOAuthConfigClass_communicate.hint=Afin d''activer l''intégration OAuth vous devez vous enregistrer pour l''accès à OAuth chez le fournisseur et insérer les informations dans les paramètres suivants.
IdentityOAuth.IdentityOAuthConfigClass_communicate.hint2=Voir aussi {0}les instructions d''installation{1}.
IdentityOAuth.IdentityOAuthConfigClass_communicate.hint=To activate an OAuth integration you need to {0}register for OAuth access to the provider''s configuration{1} and to insert your Client-Id and secret in the following settings.
IdentityOAuth.IdentityOAuthConfigClass_communicate.hint2=For more information, please see {0}the installation instructions{1}.
idoauth.webHome.1=This is the code for the Identity OAuth extension, allowing to integrate XWiki with external provider's identities.
idoauth.webHome.4=Go to Provider's section of the XWiki Preferences in order to configure the application.
	$services.localization.render('idoauth.webHome.1')
	$services.localization.render('idoauth.webHome.2')
	$services.localization.render('idoauth.webHome.3')
  $services.localization.render('idoauth.webHome.4')
[[=&gt; More about the IdentityOAuth Application>>https://store.xwiki.com/xwiki/bin/view/Extension/IdentityOAuth]].
Fixed code:     ## Handle translation prefixes.
    ## Handle extra class properties.
  ##
  ## Macros used in managing providers translations. t is for translation and tp for translation with parameters.
  ##
  #macro (getTranslation $name $usage $translation)
    #if ($usage == 'js')
      #set ($translation = $escapetool.javascript($services.localization.render($tn)))
    #else
      #set ($translation = $escapetool.xml($services.localization.render($tn)))
    #end
  ## Display translation.
  #macro (t $name $usage)
    #getTranslation($name $usage $translation)
    $translation
  #end
  ## Get translation with parameters.
  #macro (tp $name $params $usage $translation)
    #set ($msg = $services.localization.render($tn, $params))##
    #if ($usage == 'js')
      #set ($translation = $escapetool.javascript($msg))
    #else
      #set ($translation = $escapetool.xml($msg))
    #end
      #tp("redirectUrl.placeHolderMessage", ["${serverReturn}"], "js", $translation)
      window.placeHolderForRedirectUrl = "${translation}";
        #set ($successMsg = ${services.localization.render("idoauth.login.redirectmessage")})
      #set ($statusMsg = "no such identityOAuth operation '$request.identityOAuth'")
    <!-- ======= ${escapetool.xml($statusMsg)} ====== -->
IdentityOAuth.IdentityOAuthConfigClass_communicate.hint=Um eine OAuth Integration zu aktivieren, musst du {0} und die genannten Client-ID und Clientschlüssel in den folgenden Einstellungen einfügen.
IdentityOAuth.IdentityOAuthConfigClass_communicate.hint.linkLabel=dein Wiki als App für den OAuth Zugang bei dem Provider registrieren
IdentityOAuth.IdentityOAuthConfigClass_communicate.hint2=Du erhälst mehr Information in den {0}.
IdentityOAuth.IdentityOAuthConfigClass_communicate.hint2.linkLabel=Installationsanweisungen
IdentityOAuth.IdentityOAuthConfigClass_communicate.hint=Afin d''activer l''intégration OAuth vous devez {0} et insérer les informations dans les paramètres suivants.
IdentityOAuth.IdentityOAuthConfigClass_communicate.hint.linkLabel=vous enregistrer pour l''accès à OAuth chez le fournisseur
IdentityOAuth.IdentityOAuthConfigClass_communicate.hint2=Voir aussi {0}.
IdentityOAuth.IdentityOAuthConfigClass_communicate.hint2.linkLabel=les instructions d''installation
IdentityOAuth.IdentityOAuthConfigClass_communicate.hint=To activate an OAuth integration you need to {0} and to insert your Client-Id and secret in the following settings.
IdentityOAuth.IdentityOAuthConfigClass_communicate.hint.linkLabel=register for OAuth access to the provider''s configuration
IdentityOAuth.IdentityOAuthConfigClass_communicate.hint2=For more information, please see {0}.
IdentityOAuth.IdentityOAuthConfigClass_communicate.hint2.linkLabel=the installation instructions
idoauth.webHome.1=This is the code for the Identity OAuth extension, allowing to integrate XWiki with external provider identities.
idoauth.webHome.4=Go to the administration section of your specific provider in order to configure the application. 
  $escapetool.xml($services.localization.render('idoauth.webHome.1'))
  $escapetool.xml($services.localization.render('idoauth.webHome.2'))
  $escapetool.xml($services.localization.render('idoauth.webHome.3'))
  $escapetool.xml($services.localization.render('idoauth.webHome.4'))
[[=&gt; More about the IdentityOAuth Application&gt;&gt;https://store.xwiki.com/xwiki/bin/view/Extension/IdentityOAuth]].