You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by ja...@apache.org on 2026/03/11 17:57:06 UTC
(ofbiz-framework) 08/10: Fixed: Enhance sanitization of FreeMarker parameters to check both strings and lists
This is an automated email from the ASF dual-hosted git repository.
jacopoc pushed a commit to branch release24.09
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
commit fee350530775d07b9b4ff4c3a37a289affe33b8e
Author: Jacopo Cappellato <ja...@gmail.com>
AuthorDate: Wed Mar 11 08:32:45 2026 +0100
Fixed: Enhance sanitization of FreeMarker parameters to check both strings and lists
---
.../apache/ofbiz/security/SecuredFreemarker.java | 45 +++++++++++++++++-----
1 file changed, 35 insertions(+), 10 deletions(-)
diff --git a/framework/security/src/main/java/org/apache/ofbiz/security/SecuredFreemarker.java b/framework/security/src/main/java/org/apache/ofbiz/security/SecuredFreemarker.java
index b0b788d0ec..3f4961a5ad 100644
--- a/framework/security/src/main/java/org/apache/ofbiz/security/SecuredFreemarker.java
+++ b/framework/security/src/main/java/org/apache/ofbiz/security/SecuredFreemarker.java
@@ -106,26 +106,51 @@ public class SecuredFreemarker {
}
/**
- * Analyse each entry contains on params. If a freemarker template is detected, sanatize it to escape any exploit
+ * Analyzes each entry in the parameter map and sanitizes any FreeMarker interpolation expressions to prevent
+ * server-side template injection. Handles both single-value (String) and multi-value (List<String>) parameters,
+ * since submitting the same parameter name multiple times causes OFBiz to store it as a List, which would
+ * otherwise bypass a String-only check.
* @param params
* @return Map with all values sanitized
*/
public static Map<String, Object> sanitizeParameterMap(Map<String, Object> params) {
List<Map.Entry<String, Object>> unsafeEntries = params.entrySet().stream()
- .filter(entry -> entry.getValue() instanceof String
- && containsFreemarkerInterpolation((String) entry.getValue()))
+ .filter(entry -> isUnsafeValue(entry.getValue()))
.toList();
if (!unsafeEntries.isEmpty()) {
Map<String, Object> paramsSanitize = new HashMap<>(params);
- unsafeEntries.forEach(entry -> {
- String sanitazedValue = (String) entry.getValue();
- for (String interpolation : FTL_INTERPOLATION) {
- sanitazedValue = sanitazedValue.replace(interpolation, "##");
- }
- paramsSanitize.put(entry.getKey(), sanitazedValue);
- });
+ unsafeEntries.forEach(entry -> paramsSanitize.put(entry.getKey(), sanitizeValue(entry.getValue())));
return paramsSanitize;
}
return params;
}
+
+ private static boolean isUnsafeValue(Object value) {
+ if (value instanceof String s) {
+ return containsFreemarkerInterpolation(s);
+ }
+ if (value instanceof List<?> list) {
+ return list.stream().anyMatch(item -> item instanceof String s && containsFreemarkerInterpolation(s));
+ }
+ return false;
+ }
+
+ private static Object sanitizeValue(Object value) {
+ if (value instanceof String s) {
+ return sanitizeString(s);
+ }
+ if (value instanceof List<?> list) {
+ return list.stream()
+ .map(item -> item instanceof String s ? sanitizeString(s) : item)
+ .toList();
+ }
+ return value;
+ }
+
+ private static String sanitizeString(String value) {
+ for (String interpolation : FTL_INTERPOLATION) {
+ value = value.replace(interpolation, "##");
+ }
+ return value;
+ }
}