Activiti/Activiti · error · IllegalArgumentException
Illegal use of Reflection in a JUEL Expression
Error message
Illegal use of Reflection in a JUEL Expression
What it means
ELResolverReflectionBlockerDecorator wraps the JUEL ELResolver and hard-blocks any method invocation whose base object is an instance of java.lang.reflect (package java.lang.reflect), throwing IllegalArgumentException. This is a security guard: JUEL expressions in BPMN/process definitions must not be able to call arbitrary reflection APIs to bypass access control. The throw is deliberate and cannot be disabled safely.
Solutions
- Remove the reflective call from the expression and call a dedicated, allow-listed service bean method instead
- Expose a task/service delegate or Spring bean that encapsulates the logic and reference it directly in the expression
- If reflection is genuinely needed, perform it server-side in Java code, never inside a JUEL expression
- Do not remove the blocker decorator — it protects against expression injection
Example fix
// before (BPMN expression)
${execution.setVariable('x', T(java.lang.reflect.Array).newInstance(...))}
// after
${myHelperBean.computeArray(execution)} Defensive patterns
Strategy: validation
Validate before calling
boolean expressionIsSafe(String expr) {
return expr != null && !expr.matches("(?s).*java\\.reflect\\..*") && !expr.contains("forName") && !expr.contains("getMethod") && !expr.contains("invoke(");
} Try / catch
try {
Object result = valueExpression.getValue(elContext);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("Reflection")) { auditLog.security("reflection blocked in EL"); }
throw e;
} Prevention
- Never allow reflective constructs in BPMN expressions
- Validate/process-review expression strings before deployment
- Expose dedicated allow-listed beans instead of raw classes to EL
- Keep ELResolverReflectionBlockerDecorator installed in the EL resolver chain
When it happens
Trigger: A JUEL expression like ${Class.forName(...).getMethod(...).invoke(...)} or any expression whose evaluated base object's class package equals java.lang.reflect, reaching ELResolver.invoke.
Common situations: Malicious or copied expressions embedded in BPMN XML process definitions; users pasting Java-style reflective snippets into expression fields; pentest payloads like ${''.getClass().forName('java.lang.Runtime')} traversing reflective objects.
Related errors
- Illegal use of Native Method in a JUEL Expression
- Cannot find property
- error.identifier.method.notamethod
- error.value.set.rvalue
- Cannot coerce ' ' of to (incompatible type)
AI-assisted analysis of Activiti/Activiti@56435b1a97 (2026-09-09).
Data as JSON: /api/errors/0467037fb1d22bd1.
Report an issue: GitHub.
Appendix: source
Thrown at activiti-core-common/activiti-expression-language/src/main/java/org/activiti/core/el/ELResolverReflectionBlockerDecorator.java:48
public class ELResolverReflectionBlockerDecorator extends ELResolverDecorator {
private static final String JAVA_REFLECTION_PACKAGE = "java.lang.reflect";
private static final Predicate<Method> IS_FINAL = method -> Modifier.isFinal(method.getModifiers());
private static final Predicate<Method> IS_NATIVE = method -> Modifier.isNative(method.getModifiers());
private static final Set<String> NATIVE_METHODS = Arrays.stream(Object.class.getMethods())
.filter(IS_FINAL.or(IS_NATIVE))
.map(Method::getName)
.collect(Collectors.toSet());
public ELResolverReflectionBlockerDecorator(ELResolver resolver) {
super(resolver);
}
@Override
public Object invoke(ELContext context, Object base, Object method, Class<?>[] paramTypes, Object[] params) {
final String basePackageName = base.getClass().getPackageName();
if (JAVA_REFLECTION_PACKAGE.equals(basePackageName)) {
throw new IllegalArgumentException("Illegal use of Reflection in a JUEL Expression");
}
if (NATIVE_METHODS.contains(method)) {
throw new IllegalArgumentException("Illegal use of Native Method in a JUEL Expression");
}
return super.invoke(context, base, method, paramTypes, params);
}
}
View on GitHub (pinned to 56435b1a97)