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