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 <[email protected]>
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&lt;String&gt;) 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;
+    }
 }

Reply via email to