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

ashish 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 c170232f98 Improved the code of ProgramExport and did the 
sandboxing/sanitising enhancements for the groovy script use. (#984)
c170232f98 is described below

commit c170232f98efd6f7dab625f985ad2b5a134985f3
Author: Ashish Vijaywargiya <[email protected]>
AuthorDate: Sat Mar 14 15:58:08 2026 +0530

    Improved the code of ProgramExport and did the sandboxing/sanitising 
enhancements for the groovy script use. (#984)
    
    Improved the code of ProgramExport and did the sandboxing/sanitising
    enhancements for the groovy script use. Used the SecureASTCustomizer to
    limit the user operations to the application and the database only.
---
 .../ofbiz/webtools/entity/ProgramExport.groovy     | 158 ++++++++++++++++++++-
 1 file changed, 154 insertions(+), 4 deletions(-)

diff --git 
a/framework/webtools/src/main/groovy/org/apache/ofbiz/webtools/entity/ProgramExport.groovy
 
b/framework/webtools/src/main/groovy/org/apache/ofbiz/webtools/entity/ProgramExport.groovy
index e5aa213d89..693d3692e6 100644
--- 
a/framework/webtools/src/main/groovy/org/apache/ofbiz/webtools/entity/ProgramExport.groovy
+++ 
b/framework/webtools/src/main/groovy/org/apache/ofbiz/webtools/entity/ProgramExport.groovy
@@ -18,10 +18,23 @@
 */
 package org.apache.ofbiz.webtools.entity
 
+import static org.codehaus.groovy.syntax.Types.KEYWORD_IMPORT
+import static org.codehaus.groovy.syntax.Types.KEYWORD_PACKAGE
+
 import org.apache.ofbiz.entity.GenericValue
+import org.apache.ofbiz.entity.condition.EntityCondition
+import org.apache.ofbiz.entity.condition.EntityOperator
+import org.apache.ofbiz.entity.model.ModelEntity
+import org.apache.ofbiz.entity.util.EntityFindOptions
+import org.apache.ofbiz.entity.util.EntityQuery
+import org.codehaus.groovy.ast.expr.MethodPointerExpression
+import org.codehaus.groovy.ast.stmt.ForStatement
+import org.codehaus.groovy.ast.stmt.SwitchStatement
+import org.codehaus.groovy.ast.stmt.WhileStatement
 import org.codehaus.groovy.control.CompilerConfiguration
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
 import org.codehaus.groovy.control.customizers.ImportCustomizer
+import org.codehaus.groovy.control.customizers.SecureASTCustomizer
 
 String groovyProgram = null
 recordValues = []
@@ -43,14 +56,14 @@ import org.apache.ofbiz.entity.util.EntityFindOptions
 EntityFindOptions findOptions = new EntityFindOptions()
 findOptions.setMaxRows(3)
 
-List products = delegator.findList('Product', null, null, null, findOptions, 
false)
+List products = delegator.findList(\'Product\', null, null, null, findOptions, 
false)
 if (products != null) {
     recordValues.addAll(products)
 }
 
 // Get the last record created from the Product entity
-condition = EntityCondition.makeCondition('productId', 
EntityOperator.NOT_EQUAL, null)
-product = 
EntityQuery.use(delegator).from('Product').where(condition).orderBy('-productId').queryFirst()
+condition = EntityCondition.makeCondition(\'productId\', 
EntityOperator.NOT_EQUAL, null)
+product = 
EntityQuery.use(delegator).from(\'Product\').where(condition).orderBy(\'-productId\').queryFirst()
 if (product) {
     recordValues << product
 }
@@ -59,6 +72,130 @@ if (product) {
     parameters.groovyProgram = groovyProgram
 }
 
+// Dangerous Pattern Detection
+// (?s) flag for multi-line/dotall matching to prevent whitespace bypass
+List<String> dangerousPatterns = [
+        // Process & Command Execution + Runtime Variants
+        /(?s)Runtime\s*\.\s*getRuntime\s*\(\s*\)/,
+        /(?s)['"]java\.lang\.Runtime['"]\.class/,
+        /(?s)Runtime\.class\.getDeclaredMethod/,
+        /(?s)getRuntime\s*\(\s*\)\.exec/,
+        /(?s)ProcessBuilder/,
+        /(?s)\.\s*execute\s*\(/,
+        /(?s)System\s*\.\s*exit/,
+        // Reflection & ClassLoading
+        /(?s)Class\s*\.\s*forName/,
+        /(?s)\.newInstance\s*\(/,
+        /(?s)\.getDeclaredMethod/,
+        /(?s)\.getDeclaredField/,
+        /(?s)\.getMethod\s*\(/,
+        /(?s)\.getField\s*\(/,
+        /(?s)\.invoke\s*\(/,
+        /(?s)\.loadClass\s*\(/,
+        /(?s)\.getClassLoader\s*\(/,
+        /(?s)java\s*\.\s*lang\s*\.\s*reflect/,
+        /(?s)URLClassLoader/,
+        /(?s)GroovyClassLoader/,
+        /(?s)ScriptEngineManager/,
+        /(?s)javax\s*\.\s*script/,
+        /(?s)sun\s*\.\s*misc\s*\.\s*Unsafe/,
+        // Eval/GroovyShell Blocking
+        /(?s)Eval\s*\.\s*me/,
+        /(?s)Eval\s*\.\s*x/,
+        /(?s)Eval\s*\.\s*xy/,
+        /(?s)Eval\s*\.\s*xyz/,
+        /(?s)GroovyShell/,
+        /(?s)\.evaluate\s*\(/,
+        // File System Operations
+        /(?s)java\s*\.\s*io\s*\.\s*File\s*\(/,
+        /(?s)new\s+File\s*\(/,
+        /(?s)Files\s*\.\s*readAllBytes/,
+        /(?s)Paths\s*\.\s*get/,
+        /(?s)\.toFile\s*\(/,
+        /(?s)\.getResourceAsStream\s*\(/,
+        /(?s)\.getText\s*\(/,
+        /(?s)\.bytes\b/,
+        // Network Operations
+        /(?s)Socket\s*\(/,
+        /(?s)ServerSocket/,
+        /(?s)DatagramSocket/,
+        /(?s)InetSocketAddress/,
+        /(?s)InetAddress/,
+        /(?s)java\s*\.\s*net\s*\./,
+        /(?s)URL\s*\(/,
+        /(?s)NetworkInterface/,
+        /(?s)\.openConnection\s*\(/,
+        /(?s)\.connect\s*\(/,
+        // OFBiz Multitenancy Bypass
+        /(?s)DelegatorFactory/
+]
+
+for (String pattern : dangerousPatterns) {
+    if (groovyProgram =~ pattern) {
+        request.setAttribute('_ERROR_MESSAGE_', "Script contains prohibited 
pattern: ${pattern}")
+        return
+    }
+}
+
+// Groovy Sandbox with SecureASTCustomizer
+SecureASTCustomizer secureCustomizer = new SecureASTCustomizer()
+secureCustomizer.with {
+    // Import whitelist - only safe OFBiz entity classes
+    setImportsWhitelist([
+            'org.apache.ofbiz.entity.GenericValue',
+            'org.apache.ofbiz.entity.model.ModelEntity',
+            'org.apache.ofbiz.entity.condition.EntityCondition',
+            'org.apache.ofbiz.entity.condition.EntityOperator',
+            'org.apache.ofbiz.entity.util.EntityQuery',
+            'org.apache.ofbiz.entity.util.EntityFindOptions',
+            'java.util.List',
+            'java.util.Map',
+            'java.util.Set'
+    ])
+    setStarImportsWhitelist([])
+    setStaticImportsWhitelist([])
+    setStaticStarImportsWhitelist([])
+    setIndirectImportCheckEnabled(false)
+    // Constant types whitelist
+    setConstantTypesClassesWhiteList([
+            Object, String, Integer, Long, Float, Double, Boolean,
+            Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE, Boolean.TYPE,
+            BigDecimal, BigInteger,
+            Date, java.sql.Date, java.sql.Timestamp,
+            Range, IntRange,
+            GenericValue, ModelEntity,
+            EntityCondition, EntityOperator,
+            EntityQuery, EntityFindOptions,
+            List, Map, Set
+    ])
+    // Token and statement restrictions
+    setTokensBlacklist([KEYWORD_PACKAGE, KEYWORD_IMPORT])
+    setStatementsBlacklist([
+            WhileStatement, ForStatement,
+            SwitchStatement
+    ])
+    setExpressionsBlacklist([MethodPointerExpression])
+    // Receiver whitelist - only safe OFBiz entity operations
+    setReceiversWhiteList([
+            'java.lang.Object',
+            'org.apache.ofbiz.entity.Delegator',
+            'org.apache.ofbiz.entity.util.EntityQuery',
+            'org.apache.ofbiz.entity.util.EntityFindOptions',
+            'org.apache.ofbiz.entity.GenericValue',
+            'org.apache.ofbiz.entity.condition.EntityCondition',
+            'org.apache.ofbiz.entity.condition.EntityOperator',
+            'org.apache.ofbiz.entity.model.ModelEntity',
+            'java.util.List', 'java.util.Map', 'java.util.Set',
+            'java.lang.String', 'java.lang.Integer',
+            'java.lang.Long', 'java.lang.Boolean',
+            'java.util.Date', 'java.sql.Date', 'java.sql.Timestamp',
+            'java.math.BigDecimal', 'java.math.BigInteger',
+            'groovy.lang.Range', 'groovy.lang.IntRange'
+    ])
+    setClosuresAllowed(true)
+    setMethodDefinitionAllowed(false)
+}
+
 // Add imports for script.
 ImportCustomizer importCustomizer = new ImportCustomizer()
 importCustomizer.addImport('org.apache.ofbiz.entity.GenericValue')
@@ -66,8 +203,18 @@ 
importCustomizer.addImport('org.apache.ofbiz.entity.model.ModelEntity')
 importCustomizer.addImport('org.apache.ofbiz.entity.condition.EntityCondition')
 importCustomizer.addImport('org.apache.ofbiz.entity.condition.EntityOperator')
 importCustomizer.addImport('org.apache.ofbiz.entity.util.EntityQuery')
+
+// AST TRANSFORMATION BLOCKING - Disable Grape/Grab
 CompilerConfiguration configuration = new CompilerConfiguration()
+try {
+    Class grabTransform = Thread.currentThread().contextClassLoader
+            
.loadClass('org.codehaus.groovy.transform.GrabAnnotationTransformation')
+    configuration.setDisabledGlobalASTTransformations(
+            [grabTransform.name] as Set)
+} catch (ClassNotFoundException ignored) {
+}
 configuration.addCompilationCustomizers(importCustomizer)
+configuration.addCompilationCustomizers(secureCustomizer)
 
 Binding binding = new Binding()
 binding.setVariable('delegator', delegator)
@@ -87,12 +234,15 @@ if (groovyProgram) {
     } catch (MultipleCompilationErrorsException e) {
         request.setAttribute('_ERROR_MESSAGE_', e)
         return
-    } catch (groovy.lang.MissingPropertyException e) {
+    } catch (MissingPropertyException e) {
         request.setAttribute('_ERROR_MESSAGE_', e)
         return
     } catch (IllegalArgumentException e) {
         request.setAttribute('_ERROR_MESSAGE_', e)
         return
+    } catch (SecurityException e) {
+        request.setAttribute('_ERROR_MESSAGE_', 'Security violation: ' + 
e.message)
+        return
     } catch (Exception e) {
         request.setAttribute('_ERROR_MESSAGE_', e)
         return

Reply via email to