Description
Java/Jakarta Expression Language (EL) can read or modify object properties and invoke methods through expressions written as strings. Using untrusted input as expression source erases the boundary between data and executable structure, creating EL injection.
Jakarta Expression Language 6.0 imports java.lang.* by default and supports references to public static fields, methods, and constructors. The actual impact depends on the beans, functions, resolvers, and imports in the evaluation context. An attacker may read or modify accessible application data and invoke methods; exposed capabilities may also permit operating-system command execution.
The main APIs behave as follows:
| API | Expression argument | Behavior |
|---|---|---|
ELProcessor.eval(expression) |
First | Evaluates the expression immediately. |
ELProcessor.getValue(expression, type) |
First | Evaluates the expression and converts its result to the specified type. |
ELProcessor.setValue(expression, value) |
First | Evaluates the target expression and changes the final property or variable. The second argument is data. |
ELProcessor.setVariable(name, expression) |
Second | Parses an expression for later use and associates it with a variable. The first argument is the variable name. |
ExpressionFactory.createValueExpression(context, expression, type) |
Second | Parses a value expression for later evaluation. |
ExpressionFactory.createMethodExpression(context, expression, ...) |
Second | Parses a method expression for later invocation. |
javax.el is the older Java EE namespace; jakarta.el is the Jakarta EE namespace.
Potential impact
- Unauthorized reads or changes to application data exposed in the evaluation context.
- Calls to accessible objects, static methods, or constructors and misuse of application functionality.
- Operations with server privileges if file, network, or operating-system command APIs are reachable.
- Resource consumption through expensive expressions or stream operations.
Remediation
- Keep EL expression text as fixed, developer-managed strings. Do not concatenate request values or external configuration into expressions or parse and evaluate them directly.
- Bind untrusted values as data, not expression source. Use
ELProcessor.defineBeanorVariableMapper, then evaluate only fixed expressions referring to the bound values. - If users must select an operation, map a finite set of server-managed keys to reviewed constant expressions. A regular expression accepting arbitrary text or a generic escaping function does not secure the full EL grammar.
- Expose only the beans, functions, resolvers, and imports required by fixed expressions, and run with least privilege. This is defense in depth, not a sanitizer for attacker-controlled expressions.
- Remove or disable evaluation where EL is unnecessary. Jakarta EL 6.0 removed references to Java
SecurityManager; do not rely on it as a standard sandbox defense.
Examples
Before
import jakarta.el.ELProcessor;
import jakarta.servlet.http.HttpServletRequest;
final class UnsafeElEvaluation {
Object evaluate(HttpServletRequest request) {
String expression = request.getParameter("expression");
ELProcessor processor = new ELProcessor();
return processor.eval(expression); // Evaluate the request value as EL source
}
}
The request value is passed directly as the expression argument of ELProcessor.eval. An attacker can inject EL syntax selecting properties or methods accessible in that context.
After
import jakarta.el.ELProcessor;
import jakarta.servlet.http.HttpServletRequest;
final class SafeElEvaluation {
Object display(HttpServletRequest request) {
String displayName = request.getParameter("displayName");
ELProcessor processor = new ELProcessor();
processor.defineBean("displayName", displayName); // Bind the request value as data
return processor.eval("displayName"); // The developer fixes the expression
}
}
The request value is registered only as bean data, while the evaluated expression is fixed. Even when users select between functions, explicitly map each selection key to a server-managed constant expression.
Usage considerations
ExpressionFactory.create*Expression and ELProcessor.setVariable parse expressions for later use. Follow the returned expression or variable to its actual evaluation. Pass input as data to fixed expressions, and do not evaluate bound values again as expression source.
References
- Jakarta Expression Language 6.0 specification
- Jakarta EL 6.0
ELProcessorAPI - Jakarta EL 6.0
ExpressionFactoryAPI - CWE-917: Expression Language Injection
- OWASP Expression Language Injection
- OWASP Top 10:2025 A05 - Injection
- OWASP Top 10:2021 A03 - Injection
- OWASP ASVS 5.0.0 V1 - Encoding and Sanitization
- KISA Software Security Weakness Diagnosis Guide (2021)