Skip to content

VNX-JAVA-011: Java expression language injection

Reports SpEL, OGNL, Jakarta EL, ScriptEngine, MVEL, JEXL and Bean Validation message-template calls whose expression argument carries HTTP request data or the validated value, directly or through up to five local assignments. Constant expressions and request data bound as variables are not reported.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-JAVA-011
Severity Critical
SARIF level error
Kind sast
Languages Java
CWE CWE-917
CAPEC CAPEC-242
ATT&CK T1059
CWSS vector CWSS:1.0/TI:C/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:C/DI:H/EX:H/EC:N/P:W
Tags el-injection spel ognl rce
Source internal/sast/rules/vnx-java-011.rego

Overview

This rule detects instantiation and use of Spring Expression Language (SpEL) via SpelExpressionParser, OGNL evaluation via OgnlUtil or Ognl.getValue, and generic scripting engines via ScriptEngineManager or ScriptEngine.eval(), particularly when the expression string is derived from request parameters. Evaluating attacker-controlled data as a programming expression grants the same capabilities as direct code execution. This is CWE-917 (Improper Neutralization of Special Elements used in an Expression Language Statement).

Why This Matters

Expression language engines are designed to be powerful. SpEL can call arbitrary Java methods on any object in the evaluation context, including Runtime.exec(), ProcessBuilder, and reflection-based class loading. An attacker who can control the expression string can execute OS commands, read and write files, exfiltrate environment variables, and load remote classes into the JVM, all without any exploit primitive beyond the ability to submit a string.

SpEL injection has been demonstrated in high-profile CVEs: CVE-2022-22963 (Spring Cloud Function, CVSS 9.8) allowed unauthenticated RCE by sending a SpEL expression in the spring.cloud.function.routing-expression HTTP header. CVE-2018-1273 (Spring Data Commons) exploited SpEL evaluation of user-supplied property paths in Spring Data REST. OGNL injection is the mechanism behind the long series of Apache Struts RCE vulnerabilities including CVE-2017-5638 (S2-045, the Equifax breach vector).

What Gets Flagged

The rule reports the evaluation call (parseExpression, Ognl.getValue, createValueExpression, ELProcessor.eval, ScriptEngine.eval, MVEL.eval, buildConstraintViolationWithTemplate and similar) when one of its arguments is a servlet request value, an annotated handler parameter, the value a ConstraintValidator is judging, or a local assigned from one a few lines above. Creating a parser or engine, evaluating constants, and SpEL evaluated with a SimpleEvaluationContext are not reported.

// FLAGGED: SpEL parser with user input as the expression
String expr = request.getParameter("filter");
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(expr);  // RCE if expr is attacker-controlled
Object result = exp.getValue(context);

// FLAGGED: OGNL evaluation
String ognlExpr = request.getParameter("template");
Object value = Ognl.getValue(ognlExpr, context, root);

// FLAGGED: ScriptEngine with user-controlled script
ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
engine.eval(request.getParameter("script"));  // full JS engine, can call Java

// FLAGGED: JSR-245 Expression Factory
ExpressionFactory ef = ExpressionFactory.newInstance();
ef.createValueExpression(elContext, request.getParameter("el"), Object.class);

Remediation

  1. Never evaluate user input as an expression. This is the primary and most important recommendation. If you need to implement dynamic filtering, sorting, or templating based on user preferences, use a whitelist of pre-compiled expressions, not runtime evaluation of user-supplied strings.

  2. Use SimpleEvaluationContext when SpEL evaluation of data is genuinely needed. SimpleEvaluationContext provides a restricted evaluation environment that exposes only property access and configured operators, it does not allow method invocations, type references, or constructor calls. Use it instead of StandardEvaluationContext for any expression derived from external input.

    // SAFER: SimpleEvaluationContext limits what SpEL can do
    // Still, do not use user input as the expression. Use it only for
    // expressions you control, against data objects the user provides.
    ExpressionParser parser = new SpelExpressionParser();
    Expression expression = parser.parseExpression("firstName + ' ' + lastName");
    
    SimpleEvaluationContext context = SimpleEvaluationContext
        .forReadOnlyDataBinding()
        .withRootObject(userSuppliedData)  // data from user, not the expression
        .build();
    
    String result = expression.getValue(context, String.class);
  3. For dynamic filtering or querying, use a purpose-built safe API. Spring Data’s Specification API, QueryDSL predicates, or RSQL parsers provide safe, typed query construction that cannot execute arbitrary code.

    // SAFE: QueryDSL predicate, user controls values, not code
    QProduct product = QProduct.product;
    BooleanExpression predicate = product.category.eq(request.getParameter("category"))
        .and(product.price.lt(new BigDecimal(request.getParameter("maxPrice"))));
    productRepository.findAll(predicate);
  4. Disable or sandbox ScriptEngine use entirely. If you need server-side scripting by end users, use a purpose-built sandboxed interpreter (such as GraalVM’s Polyglot sandbox with resource limits, or a separate isolated process with no filesystem or network access). Standard javax.script engines run in the same JVM with full permissions.

  5. Audit all uses of @Value annotations with SpEL. Spring’s @Value("#{...}") annotations support SpEL. Ensure no @Value expression includes a property sourced from external, user-controllable configuration. Prefer @Value("${property.name}") (property placeholder, not expression) for simple value injection.

References

Suppressing this rule

Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):

# nosec vnx-java-011
// nosec vnx-java-011

Or record an ignore rule: vulnetix ignore add --rule vnx-java-011 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-java-011.rego, cli/internal/sast/docs/vnx-java-011.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.