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
@@ -30,6 +30,8 @@
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;
@@ -66,6 +68,13 @@ public class EscapeTool extends org.apache.velocity.tools.generic.EscapeTool
/** And sign. */
private static final String AND = "&";
+ private static final CharSequenceTranslator XWIKI_ESCAPE_HTML4 = StringEscapeUtils.ESCAPE_HTML4.with(
+ new LookupTranslator(Map.ofEntries(
+ Map.entry("{", "{"),
+ Map.entry("}", "}")
+ ))
+ );
+
/**
* Change the default key defined in {@link org.apache.velocity.tools.generic.EscapeTool}.
*/
@@ -74,6 +83,24 @@ public EscapeTool()
setKey(DEFAULT_KEY);
}
+ /**
+ * Escapes the HTML special characters in a String
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 String
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
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
@@ -259,4 +259,12 @@ void velocity()
{
assertEquals("one${escapetool.h}${escapetool.h}two", this.tool.velocity("one##two"));
}
+
+ @Test
+ void html()
+ {
+ assertEquals("<script>alert("Hello, <World>!");</script>{{"
+ + "/html}}",
+ this.tool.html("{{/html}}"));
+ }
}