This is an automated email from the ASF dual-hosted git repository.

jacopoc pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 6d67f2576c Improved: Enhance GroovyUtil with secure AST customizations 
for eval() expressions to implement an execution sandbox
6d67f2576c is described below

commit 6d67f2576cca28d7eb47053807a65581bd468264
Author: Jacopo Cappellato <[email protected]>
AuthorDate: Wed Mar 11 08:26:26 2026 +0100

    Improved: Enhance GroovyUtil with secure AST customizations for eval() 
expressions to implement an execution sandbox
---
 .../org/apache/ofbiz/base/util/GroovyUtil.java     | 43 +++++++++++++++++++++-
 1 file changed, 41 insertions(+), 2 deletions(-)

diff --git 
a/framework/base/src/main/java/org/apache/ofbiz/base/util/GroovyUtil.java 
b/framework/base/src/main/java/org/apache/ofbiz/base/util/GroovyUtil.java
index 4351dfac9b..cf9f3c7d65 100644
--- a/framework/base/src/main/java/org/apache/ofbiz/base/util/GroovyUtil.java
+++ b/framework/base/src/main/java/org/apache/ofbiz/base/util/GroovyUtil.java
@@ -21,7 +21,9 @@ package org.apache.ofbiz.base.util;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import javax.script.ScriptContext;
@@ -30,6 +32,7 @@ import org.apache.ofbiz.base.location.FlexibleLocation;
 import org.apache.ofbiz.base.util.cache.UtilCache;
 import org.codehaus.groovy.control.CompilationFailedException;
 import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.control.customizers.SecureASTCustomizer;
 import org.codehaus.groovy.runtime.InvokerHelper;
 
 import groovy.lang.Binding;
@@ -46,6 +49,7 @@ public final class GroovyUtil {
     private static final String MODULE = GroovyUtil.class.getName();
     private static final UtilCache<String, Class<?>> PARSED_SCRIPTS = 
UtilCache.createUtilCache("script.GroovyLocationParsedCache", 0, 0, false);
     private static final GroovyClassLoader GROOVY_CLASS_LOADER;
+    private static final CompilerConfiguration SANDBOXED_COMPILER_CONFIG;
 
     private GroovyUtil() { }
 
@@ -60,8 +64,43 @@ public final class GroovyUtil {
         GROOVY_CLASS_LOADER = groovyClassLoader;
     }
 
+    static {
+        // Compile-time AST restrictions applied to eval() expressions.
+        // Blocks OS-execution APIs and dynamic class-loading as a 
defence-in-depth measure.
+        // Note: SecureASTCustomizer operates at compile time and does not 
constitute a
+        // complete sandbox; eval() expressions should never originate from 
untrusted input.
+        SecureASTCustomizer secureAst = new SecureASTCustomizer();
+        secureAst.setDisallowedImports(List.of(
+                "java.lang.Runtime",
+                "java.lang.ProcessBuilder",
+                "java.lang.ClassLoader",
+                "java.lang.Thread",
+                "java.lang.reflect.Method",
+                "java.lang.reflect.Field",
+                "java.net.Socket",
+                "java.net.ServerSocket",
+                "groovy.lang.GroovyShell",
+                "groovy.lang.GroovyClassLoader"));
+        @SuppressWarnings("rawtypes")
+        List<Class> blockedReceivers = Arrays.asList(
+                Runtime.class,
+                ProcessBuilder.class,
+                Thread.class,
+                ClassLoader.class);
+        secureAst.setDisallowedReceiversClasses(blockedReceivers);
+        SANDBOXED_COMPILER_CONFIG = new CompilerConfiguration();
+        SANDBOXED_COMPILER_CONFIG.addCompilationCustomizers(secureAst);
+    }
+
     /**
-     * Evaluate a Groovy condition or expression
+     * Evaluate a Groovy condition or expression.
+     * <p>The shell is created with a restricted {@link CompilerConfiguration} 
backed by
+     * {@link SecureASTCustomizer}: explicit imports of OS-execution and 
dynamic class-loading
+     * APIs ({@code Runtime}, {@code ProcessBuilder}, {@code Thread}, {@code 
ClassLoader} and
+     * related reflection / network classes) are disallowed, and those same 
types are blocked
+     * as method-call receivers.  This is a compile-time, defence-in-depth 
measure; it does
+     * not constitute a complete sandbox, and expressions must never originate 
from untrusted
+     * user input.
      * @param expression The expression to evaluate
      * @param context The context to use in evaluation (re-written)
      * @see <a 
href="StringUtil.html#convertOperatorSubstitutions(java.lang.String)">StringUtil.convertOperatorSubstitutions(java.lang.String)</a>
@@ -80,7 +119,7 @@ public final class GroovyUtil {
             Debug.logVerbose("Using Context -- " + context, MODULE);
         }
         try {
-            GroovyShell shell = new GroovyShell(getBinding(context, 
expression));
+            GroovyShell shell = new 
GroovyShell(GroovyUtil.class.getClassLoader(), getBinding(context, expression), 
SANDBOXED_COMPILER_CONFIG);
             o = 
shell.evaluate(StringUtil.convertOperatorSubstitutions(expression));
             if (Debug.verboseOn()) {
                 Debug.logVerbose("Evaluated to -- " + o, MODULE);

Reply via email to