CVE-2024-31996: Insufficient Information (NVD-CWE-noinfo)
value: XWiki Platform is a generic wiki platform. Starting in version 3.0.1 and prior to versions 4.10.19, 15.5.4, and 15.10-rc-1, the HTML escaping of escaping tool that is used in XWiki doesn't escape `{`, which, when used in certain places, allows XWiki syntax injection and thereby remote code execution. The vulnerability has been fixed in XWiki 14.10.19, 15.5.5, and 15.9 RC1. Apart from upgrading, there is no generic workaround. However, replacing `$escapetool.html` by `$escapetool.xml` in XWiki documents fixes the vulnerability. In a standard XWiki installation, the maintainers are only aware of the document `Panels.PanelLayoutUpdate` that exposes this vulnerability, patching this document is thus a workaround. Any extension could expose this vulnerability and might thus require patching, too.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-04-10T21:15Z
Repository: https://github.com/xwiki/xwiki-commons
Language: Java
Files changed: xwiki-commons-core/xwiki-commons-velocity/src/main/java/org/xwiki/velocity/tools/EscapeTool.java, xwiki-commons-core/xwiki-commons-velocity/src/test/java/org/xwiki/velocity/tools/EscapeToolTest.java
Commit date: 2023-10-20 17:45:26 +0200
Commit message: XCOMMONS-2828: Support curly braces in `EscapeTool.html()`

Diff: diff --git a/xwiki-commons-core/xwiki-commons-velocity/src/main/java/org/xwiki/velocity/tools/EscapeTool.java b/xwiki-commons-core/xwiki-commons-velocity/src/main/java/org/xwiki/velocity/tools/EscapeTool.java
index 60ffb3463f..3fe2f17098 100644
--- a/xwiki-commons-core/xwiki-commons-velocity/src/main/java/org/xwiki/velocity/tools/EscapeTool.java
+++ b/xwiki-commons-core/xwiki-commons-velocity/src/main/java/org/xwiki/velocity/tools/EscapeTool.java
@@ -28,10 +28,12 @@
 import org.apache.commons.codec.EncoderException;
 import org.apache.commons.codec.net.BCodec;
 import org.apache.commons.codec.net.QCodec;
 import org.apache.commons.codec.net.QuotedPrintableCodec;
 import org.apache.commons.text.StringEscapeUtils;
+import org.apache.commons.text.translate.CharSequenceTranslator;
+import org.apache.commons.text.translate.LookupTranslator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.xwiki.xml.XMLUtils;
 
 /**
@@ -64,18 +66,43 @@ public class EscapeTool extends org.apache.velocity.tools.generic.EscapeTool
     private static final String EQUALS = "=";
 
     /** And sign. */
     private static final String AND = "&";
 
+    private static final CharSequenceTranslator XWIKI_ESCAPE_HTML4 = StringEscapeUtils.ESCAPE_HTML4.with(
+        new LookupTranslator(Map.ofEntries(
+            Map.entry("{", "&lcub;"),
+            Map.entry("}", "&rcub;")
+        ))
+    );
+
     /**
      * Change the default key defined in {@link org.apache.velocity.tools.generic.EscapeTool}.
      */
     public EscapeTool()
     {
         setKey(DEFAULT_KEY);
     }
 
+    /**
+     * Escapes the HTML special characters in a <code>String</code> using HTML entities. This overrides the base
+     * implementation from Velocity in order to also escape characters potentially harmful in the context of XWiki,
+     * such as curly brackets.
+     *
+     * @param content the string to escape, may be {@code null}
+     * @return a new escaped {@code String}, {@code null} if {@code null} input
+     */
+    @Override
+    public String html(Object content)
+    {
+        if (content == null)
+        {
+            return null;
+        }
+        return XWIKI_ESCAPE_HTML4.translate(String.valueOf(content));
+    }
+
     /**
      * Escapes the XML special characters in a <code>String</code> using numerical XML entities. This overrides the base
      * implementation from Velocity, which is over-zealous and escapes any non-ASCII character. Since XWiki works with
      * Unicode-capable encodings (UTF-8), there is no need to escape non-special characters.
      *
diff --git a/xwiki-commons-core/xwiki-commons-velocity/src/test/java/org/xwiki/velocity/tools/EscapeToolTest.java b/xwiki-commons-core/xwiki-commons-velocity/src/test/java/org/xwiki/velocity/tools/EscapeToolTest.java
index 523cc78a5d..456ceb5e75 100644
--- a/xwiki-commons-core/xwiki-commons-velocity/src/test/java/org/xwiki/velocity/tools/EscapeToolTest.java
+++ b/xwiki-commons-core/xwiki-commons-velocity/src/test/java/org/xwiki/velocity/tools/EscapeToolTest.java
@@ -257,6 +257,14 @@ void css()
     @Test
     void velocity()
     {
         assertEquals("one${escapetool.h}${escapetool.h}two", this.tool.velocity("one##two"));        
     }
+
+    @Test
+    void html()
+    {
+        assertEquals("&lt;script&gt;alert(&quot;Hello, &amp;lt;World&amp;gt;!&quot;);&lt;/script&gt;&lcub;&lcub;"
+                + "/html&rcub;&rcub;",
+            this.tool.html("<script>alert(\"Hello, &lt;World&gt;!\");</script>{{/html}}"));
+    }
 }

Fixed code: import org.apache.commons.text.translate.CharSequenceTranslator;
import org.apache.commons.text.translate.LookupTranslator;
    private static final CharSequenceTranslator XWIKI_ESCAPE_HTML4 = StringEscapeUtils.ESCAPE_HTML4.with(
        new LookupTranslator(Map.ofEntries(
            Map.entry("{", "&lcub;"),
            Map.entry("}", "&rcub;")
        ))
    );

    /**
     * Escapes the HTML special characters in a <code>String</code> using HTML entities. This overrides the base
     * implementation from Velocity in order to also escape characters potentially harmful in the context of XWiki,
     * such as curly brackets.
     *
     * @param content the string to escape, may be {@code null}
     * @return a new escaped {@code String}, {@code null} if {@code null} input
     */
    @Override
    public String html(Object content)
    {
        if (content == null)
        {
            return null;
        }
        return XWIKI_ESCAPE_HTML4.translate(String.valueOf(content));
    }


    @Test
    void html()
    {
        assertEquals("&lt;script&gt;alert(&quot;Hello, &amp;lt;World&amp;gt;!&quot;);&lt;/script&gt;&lcub;&lcub;"
                + "/html&rcub;&rcub;",
            this.tool.html("<script>alert(\"Hello, &lt;World&gt;!\");</script>{{/html}}"));
    }