Skip to content

[Vulnerability] SpEL Injection in baomidou_dynamic-datasource #766

@wing3e

Description

@wing3e

SpEL Injection in baomidou_dynamic-datasource

Identification

Description

dynamic-datasource evaluates @DS values as SpEL expressions in DsSpelExpressionProcessor#doDetermineDatasource using StandardEvaluationContext and SpelExpressionParser without input restriction. When applications use patterns like @DS("#tenant") and bind tenant from untrusted request input, attacker-controlled expressions can be evaluated at runtime. This enables expression injection and can lead to remote code execution depending on runtime exposure and expression payload.

Affected Component

  • File(s): dynamic-datasource-spring/src/main/java/com/baomidou/dynamic/datasource/processor/DsSpelExpressionProcessor.java, dynamic-datasource-spring/src/main/java/com/baomidou/dynamic/datasource/annotation/DS.java
  • Function / Method: DsSpelExpressionProcessor#doDetermineDatasource
  • Entry Point: @DS annotation value (including SpEL form), often via method parameters mapped from HTTP input

Reproduction Summary

  1. Application code uses @DS("#param") and param is user-controlled.
  2. Request sends an expression payload such as T(java.lang.Runtime).getRuntime().exec('calc') in that parameter.
  3. Framework evaluates the expression in doDetermineDatasource, causing expression execution and potential RCE.

Technical Details

// Raw report evidence
@Override
public String doDetermineDatasource(MethodInvocation invocation, String key) {
    Method method = invocation.getMethod();
    Object[] arguments = invocation.getArguments();
    ExpressionRootObject rootObject = new ExpressionRootObject(method, arguments, invocation.getThis());
    StandardEvaluationContext context = new MethodBasedEvaluationContext(rootObject, method, arguments, NAME_DISCOVERER);
    context.setBeanResolver(beanResolver);
    final Object value = PARSER.parseExpression(key, parserContext).getValue(context);  // VULNERABLE
    return value == null ? null : value.toString();
}

// Raw report PoC payload path
GET /api/users?dsName=T(java.lang.Runtime).getRuntime().exec('calc')

PARSER.parseExpression("T(java.lang.Runtime).getRuntime().exec('calc')").getValue(context)

Validation Notes

// Source code verification from project
public @interface DS {
    /**
     * groupName or specific database name or spring SPEL name.
     */
    String value();
}

@Override
public String doDetermineDatasource(MethodInvocation invocation, String key) {
    Method method = invocation.getMethod();
    Object[] arguments = invocation.getArguments();
    ExpressionRootObject rootObject = new ExpressionRootObject(method, arguments, invocation.getThis());
    StandardEvaluationContext context = new MethodBasedEvaluationContext(rootObject, method, arguments, NAME_DISCOVERER);
    context.setBeanResolver(beanResolver);
    final Object value = PARSER.parseExpression(key, parserContext).getValue(context);
    return value == null ? null : value.toString();
}

// [Reviewer Evidence] CVE analogy in review
// Comparison to Known CVEs
// - CVE-2011-2730: Spring Framework SpEL injection
// - CVE-2018-1270: Spring Messaging SpEL injection

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions