java.spring.security.audit.spel-injection.spel-injection

Community Favorite
profile photo of semgrepsemgrep
Author
50,762
Download Count*

A Spring expression is built with a dynamic value. The source of the value(s) should be verified to avoid that unfiltered values fall into this risky code evaluation.

Run Locally

Run in CI

Defintion

rules:
  - id: spel-injection
    message: A Spring expression is built with a dynamic value. The source of the
      value(s) should be verified to avoid that unfiltered values fall into this
      risky code evaluation.
    metadata:
      cwe:
        - "CWE-94: Improper Control of Generation of Code ('Code Injection')"
      owasp:
        - A03:2021 - Injection
      source-rule-url: https://find-sec-bugs.github.io/bugs.htm#SPEL_INJECTION
      category: security
      technology:
        - spring
      references:
        - https://owasp.org/Top10/A03_2021-Injection
      cwe2022-top25: true
      subcategory:
        - audit
      likelihood: LOW
      impact: HIGH
      confidence: LOW
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Code Injection
    severity: WARNING
    languages:
      - java
    patterns:
      - pattern-either:
          - pattern-inside: |
              class $CLASS {
                ...
                ExpressionParser $PARSER;
                ...
              }
          - pattern-inside: |
              class $CLASS {
                ...
                ExpressionParser $PARSER = ...;
                ...
              }
          - pattern-inside: |
              $X $METHOD(...) {
                ...
                ExpressionParser $PARSER = ...;
                ...
              }
          - pattern-inside: |
              class $CLASS {
                ...
                SpelExpressionParser $PARSER;
                ...
              }
          - pattern-inside: |
              class $CLASS {
                ...
                SpelExpressionParser $PARSER = ...;
                ...
              }
          - pattern-inside: |
              $X $METHOD(...) {
                ...
                SpelExpressionParser $PARSER = ...;
                ...
              }
          - pattern-inside: |
              class $CLASS {
                ...
                TemplateAwareExpressionParser $PARSER;
                ...
              }
          - pattern-inside: |
              class $CLASS {
                ...
                TemplateAwareExpressionParser $PARSER = ...;
                ...
              }
          - pattern-inside: |
              $X $METHOD(...) {
                ...
                TemplateAwareExpressionParser $PARSER = ...;
                ...
              }
      - pattern: |
          $X $METHOD(...) {
            ...
            $PARSER.parseExpression(...);
            ...
          }
      - pattern-not: |
          $X $METHOD(...) {
            ...
            $PARSER.parseExpression("...");
            ...
          }
      - pattern-not: |
          $X $METHOD(...) {
            ...
            String $S = "...";
            ...
            $PARSER.parseExpression($S);
            ...
          }

Examples

spel-injection.java

package testcode.script;


import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.TemplateAwareExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class SpelSample {

    private static PersonDTO TEST_PERSON = new PersonDTO("Benoit", "Doudou");

    // ruleid: spel-injection
    public static void parseExpressionInterface1(String property) {
        ExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext testContext = new StandardEvaluationContext(TEST_PERSON);
        Expression exp2 = parser.parseExpression(property+" == 'Benoit'");
        String dynamicValue = exp2.getValue(testContext, String.class);
        System.out.println("exp2="+dynamicValue);
    }

    // ok: spel-injection
    public static void parseExpressionInterface2(String property) {
        ExpressionParser parser = new SpelExpressionParser();
        Expression exp1 = parser.parseExpression("'safe expression'");
        String constantValue = exp1.getValue(String.class);
        System.out.println("exp1="+constantValue);
    }

    // ruleid: spel-injection
    public static void parseSpelExpression3(String property) {
        SpelExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext testContext = new StandardEvaluationContext(TEST_PERSON);
        Expression exp2 = parser.parseExpression(property+" == 'Benoit'");
        String dynamicValue = exp2.getValue(testContext, String.class);
        System.out.println("exp2=" + dynamicValue);
    }

    // ok: spel-injection
    public static void parseSpelExpression4(String property) {
        SpelExpressionParser parser = new SpelExpressionParser();
        Expression exp1 = parser.parseExpression("'safe expression'");
        String constantValue = exp1.getValue(String.class);
        System.out.println("exp1="+constantValue);
    }

    // ok: spel-injection
    public static void parseTemplateAwareExpression1(String property) {
        TemplateAwareExpressionParser parser = new SpelExpressionParser();
        Expression exp1 = parser.parseExpression("'safe expression'");
        String constantValue = exp1.getValue(String.class);
        System.out.println("exp1="+constantValue);
    }

    // ruleid: spel-injection
    public static void parseTemplateAwareExpression2(String property) {
        TemplateAwareExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext testContext = new StandardEvaluationContext(TEST_PERSON);
        Expression exp2 = parser.parseExpression(property+" == 'Benoit'");
        String dynamicValue = exp2.getValue(testContext, String.class);
        System.out.println("exp2="+dynamicValue);
    }

    public static void main(String[] args) {
        //Expected use case..
        parseExpressionInterface("firstName");
        //Malicious use case..
        parseExpressionInterface("T(java.lang.Runtime).getRuntime().exec('calc.exe')");
    }

    static class PersonDTO {
        public final String firstName;
        public final String lastName;

        public PersonDTO(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
    }
}