CVE-2023-29516: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection') (CWE-74)
value: XWiki Platform is a generic wiki platform offering runtime services for applications built on top of it. Any user with view rights on `XWiki.AttachmentSelector` can execute arbitrary Groovy, Python or Velocity code in XWiki leading to full access to the XWiki installation. The root cause is improper escaping in the "Cancel and return to page" button. This page is installed by default. This vulnerability has been patched in XWiki 15.0-rc-1, 14.10.1, 14.4.8, and 13.10.11. There are no known workarounds for this vulnerability.

CWE description: The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component.
CVSS v3 base score: 8.8
Published: 2023-04-19T00:15Z
Repository: https://github.com/xwiki/xwiki-platform
Language: XML
Files changed: xwiki-platform-core/xwiki-platform-attachment/xwiki-platform-attachment-ui/src/main/resources/XWiki/AttachmentSelector.xml, xwiki-platform-core/xwiki-platform-attachment/xwiki-platform-attachment-ui/src/test/java/org/xwiki/attachment/AttachmentSelectorPageTest.java
Commit date: 2022-12-02 14:28:11 +0100
Commit message: XWIKI-20275: Improved escaping on XWiki.AttachmentSelector

Diff: diff --git a/xwiki-platform-core/xwiki-platform-attachment/xwiki-platform-attachment-ui/src/main/resources/XWiki/AttachmentSelector.xml b/xwiki-platform-core/xwiki-platform-attachment/xwiki-platform-attachment-ui/src/main/resources/XWiki/AttachmentSelector.xml
index d39e265e68a25..a79736611053a 100644
--- a/xwiki-platform-core/xwiki-platform-attachment/xwiki-platform-attachment-ui/src/main/resources/XWiki/AttachmentSelector.xml
+++ b/xwiki-platform-core/xwiki-platform-attachment/xwiki-platform-attachment-ui/src/main/resources/XWiki/AttachmentSelector.xml
@@ -369,12 +369,14 @@
     'versionSummary': $request.versionSummary.equals('true')
   })
   $!targetDocument.use($targetDocument.getObject($options.classname, $options.object))##
   #attachmentPicker_displayAttachmentGallery($targetDocument, $targetAttachDocument, $options)
 
+  #set ($cancelLinkName = $services.rendering.escape($services.rendering.escape($services.localization.render("${translationPrefix}.cancel"), 'xwiki/2.1'), 'xwiki/2.1'))
+  #set ($cancelLinkTarget = $services.rendering.escape($services.model.serialize($targetDocument), 'xwiki/2.1'))
   (% class="gallery_buttons buttons" %)(((
-  (% class="buttonwrapper secondary" %)[[$services.localization.render("${translationPrefix}.cancel")&gt;&gt;${targetDocument}||class="button secondary" id="attachment-picker-close"]]
+  (% class="buttonwrapper secondary" %)[[$cancelLinkName&gt;&gt;$cancelLinkTarget||class="button secondary" id="attachment-picker-close"]]
   )))
 #end
 {{/velocity}}</content>
   <object>
     <name>XWiki.AttachmentSelector</name>
diff --git a/xwiki-platform-core/xwiki-platform-attachment/xwiki-platform-attachment-ui/src/test/java/org/xwiki/attachment/AttachmentSelectorPageTest.java b/xwiki-platform-core/xwiki-platform-attachment/xwiki-platform-attachment-ui/src/test/java/org/xwiki/attachment/AttachmentSelectorPageTest.java
index 392dadb4754d5..cb6db380a11f3 100644
--- a/xwiki-platform-core/xwiki-platform-attachment/xwiki-platform-attachment-ui/src/test/java/org/xwiki/attachment/AttachmentSelectorPageTest.java
+++ b/xwiki-platform-core/xwiki-platform-attachment/xwiki-platform-attachment-ui/src/test/java/org/xwiki/attachment/AttachmentSelectorPageTest.java
@@ -38,10 +38,11 @@
 import org.xwiki.bridge.event.DocumentCreatedEvent;
 import org.xwiki.component.manager.ComponentManager;
 import org.xwiki.component.wiki.internal.bridge.DefaultContentParser;
 import org.xwiki.icon.IconManagerScriptService;
 import org.xwiki.icon.internal.DefaultIconManagerComponentList;
+import org.xwiki.model.internal.reference.converter.EntityReferenceConverter;
 import org.xwiki.model.reference.AttachmentReference;
 import org.xwiki.model.reference.DocumentReference;
 import org.xwiki.model.script.ModelScriptService;
 import org.xwiki.observation.EventListener;
 import org.xwiki.rendering.RenderingScriptServiceComponentList;
@@ -108,11 +109,13 @@
     org.xwiki.rendering.internal.parser.DefaultContentParser.class,
     DefaultWikiMacroRenderer.class,
     // End WikiMacroEventListener
     TemporaryAttachmentsScriptService.class,
     IconManagerScriptService.class,
-    DocumentReferenceConverter.class
+    DocumentReferenceConverter.class,
+    EntityReferenceConverter.class,
+    ModelScriptService.class,
 })
 class AttachmentSelectorPageTest extends PageTest
 {
     /**
      * Mocked because we don't want to deal with actual sessions for this test.
@@ -334,10 +337,21 @@ void withTemporaryAttachment() throws Exception
             String.format("temporary_attachment class not found in %s", element.classNames()));
         assertNotNull(element.selectFirst(".fake-attach"), "An icon with class fake-attach is expected to "
             + "be found");
     }
 
+    @Test
+    void cancelButton() throws Exception
+    {
+        commonFixup("test.png");
+
+        this.request.put("docname", "xwiki:Space.]] {{noscript/}}");
+
+        Document document = renderHTMLPage(new DocumentReference("xwiki", "XWiki", "AttachmentSelector"));
+        assertEquals("Space.]] {{noscript/}}", document.getElementById("attachment-picker-close").attr("href"));
+    }
+
     private void attachmentSelectorMacroFixup() throws Exception
     {
         DocumentReference attachmentSelectorDocumentReference =
             new DocumentReference("xwiki", "XWiki", "AttachmentSelector");
         XWikiDocument xWikiDocument = loadPage(attachmentSelectorDocumentReference);

Vulnerable code:   (% class="buttonwrapper secondary" %)[[$services.localization.render("${translationPrefix}.cancel")&gt;&gt;${targetDocument}||class="button secondary" id="attachment-picker-close"]]
    DocumentReferenceConverter.class
Fixed code:   #set ($cancelLinkName = $services.rendering.escape($services.rendering.escape($services.localization.render("${translationPrefix}.cancel"), 'xwiki/2.1'), 'xwiki/2.1'))
  #set ($cancelLinkTarget = $services.rendering.escape($services.model.serialize($targetDocument), 'xwiki/2.1'))
  (% class="buttonwrapper secondary" %)[[$cancelLinkName&gt;&gt;$cancelLinkTarget||class="button secondary" id="attachment-picker-close"]]
import org.xwiki.model.internal.reference.converter.EntityReferenceConverter;
    DocumentReferenceConverter.class,
    EntityReferenceConverter.class,
    ModelScriptService.class,
    @Test
    void cancelButton() throws Exception
    {
        commonFixup("test.png");

        this.request.put("docname", "xwiki:Space.]] {{noscript/}}");

        Document document = renderHTMLPage(new DocumentReference("xwiki", "XWiki", "AttachmentSelector"));
        assertEquals("Space.]] {{noscript/}}", document.getElementById("attachment-picker-close").attr("href"));
    }