CVE-2022-1782: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Cross-site Scripting (XSS) - Generic in GitHub repository erudika/para prior to v1.45.11.
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: 6.1
Published: 2022-05-18T15:15Z
Repository: https://github.com/erudika/para
Language: Java
Files changed: para-core/src/main/java/com/erudika/para/core/utils/Utils.java, para-server/src/test/java/com/erudika/para/core/utils/UtilsTest.java
Commit date: 2022-05-16 19:19:47 +0300
Commit message: added option to escape HTML when compiling Mustache templates

Diff: diff --git a/para-core/src/main/java/com/erudika/para/core/utils/Utils.java b/para-core/src/main/java/com/erudika/para/core/utils/Utils.java
index 3e030df7..6ba617dd 100644
--- a/para-core/src/main/java/com/erudika/para/core/utils/Utils.java
+++ b/para-core/src/main/java/com/erudika/para/core/utils/Utils.java
@@ -328,27 +328,37 @@ public final class Utils {
 	 * Compiles a mustache template with a given scope (map of fields and values).
 	 * @param context a map of fields and values
 	 * @param template a Mustache template
 	 * @return the compiled template string
 	 */
-	public static String compileMustache(Map<String, Object> context, String template) {
+	public static String compileMustache(Map<String, Object> context, String template, boolean escapeHtml) {
 		if (context == null || StringUtils.isBlank(template)) {
 			return "";
 		}
 		Writer writer = new StringWriter();
 		try {
-			Mustache.compiler().escapeHTML(false).emptyStringIsFalse(true).compile(template).execute(context, writer);
+			Mustache.compiler().escapeHTML(escapeHtml).emptyStringIsFalse(true).compile(template).execute(context, writer);
 		} finally {
 			try {
 				writer.close();
 			} catch (IOException e) {
 				logger.error(null, e);
 			}
 		}
 		return writer.toString();
 	}
 
+	/**
+	 * @see #compileMustache(java.util.Map, java.lang.String, boolean)
+	 * @param context a map of fields and values
+	 * @param template a Mustache template
+	 * @return the compiled template string
+	 */
+	public static String compileMustache(Map<String, Object> context, String template) {
+		return compileMustache(context, template, false);
+	}
+
 	/**
 	 * Abbreviates a string.
 	 * @param str a string
 	 * @param max max length
 	 * @return a substring of that string
diff --git a/para-server/src/test/java/com/erudika/para/core/utils/UtilsTest.java b/para-server/src/test/java/com/erudika/para/core/utils/UtilsTest.java
index 0f7021aa..a9f3e236 100644
--- a/para-server/src/test/java/com/erudika/para/core/utils/UtilsTest.java
+++ b/para-server/src/test/java/com/erudika/para/core/utils/UtilsTest.java
@@ -15,21 +15,19 @@
  *
  * For issues and patches go to: https://github.com/erudika
  */
 package com.erudika.para.core.utils;
 
-import com.erudika.para.core.utils.Config;
-import com.erudika.para.core.utils.Utils;
-import com.erudika.para.core.annotations.Locked;
 import com.erudika.para.core.App;
 import com.erudika.para.core.ParaObject;
 import com.erudika.para.core.Sysprop;
 import com.erudika.para.core.Tag;
 import com.erudika.para.core.User;
 import com.erudika.para.core.Votable;
-import static com.erudika.para.core.utils.Utils.*;
+import com.erudika.para.core.annotations.Locked;
 import static com.erudika.para.core.utils.ParaObjectUtils.*;
+import static com.erudika.para.core.utils.Utils.*;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -112,10 +110,12 @@ public class UtilsTest {
 		assertNotNull(compileMustache(null, ""));
 		assertNotNull(compileMustache(new HashMap<>(), "test"));
 		Map<String, Object> map = new HashMap<>();
 		map.put("test", "string");
 		assertEquals("<html>string</html>", compileMustache(map, "<html>{{test}}</html>"));
+		map.put("test", "<b>string</b>");
+		assertEquals("<html>&lt;b&gt;string&lt;/b&gt;</html>", compileMustache(map, "<html>{{test}}</html>", true));
 	}
 
 	@Test
 	public void testAbbreviate() {
 		assertNotNull(abbreviate(null, 0));

Vulnerable code: 	public static String compileMustache(Map<String, Object> context, String template) {
			Mustache.compiler().escapeHTML(false).emptyStringIsFalse(true).compile(template).execute(context, writer);
import com.erudika.para.core.utils.Config;
import com.erudika.para.core.utils.Utils;
import com.erudika.para.core.annotations.Locked;
import static com.erudika.para.core.utils.Utils.*;
Fixed code: 	public static String compileMustache(Map<String, Object> context, String template, boolean escapeHtml) {
			Mustache.compiler().escapeHTML(escapeHtml).emptyStringIsFalse(true).compile(template).execute(context, writer);
	/**
	 * @see #compileMustache(java.util.Map, java.lang.String, boolean)
	 * @param context a map of fields and values
	 * @param template a Mustache template
	 * @return the compiled template string
	 */
	public static String compileMustache(Map<String, Object> context, String template) {
		return compileMustache(context, template, false);
	}

import com.erudika.para.core.annotations.Locked;
import static com.erudika.para.core.utils.Utils.*;
		map.put("test", "<b>string</b>");
		assertEquals("<html>&lt;b&gt;string&lt;/b&gt;</html>", compileMustache(map, "<html>{{test}}</html>", true));