Skip to content

Question: is SpEL evaluation in NacosUtils.evaluate (StandardEvaluationContext) a security concern? (re: EL feature #217 / Nacos config-center attack surface) #363

@cybervuln2077

Description

@cybervuln2077

Question / security inquiry — SpEL evaluation in NacosUtils.evaluate (StandardEvaluationContext)

This is a question, not an assertion that a vulnerability exists. NacosUtils evaluates a
configuration string as a Spring Expression Language (SpEL) template in an unrestricted
StandardEvaluationContext, and we'd like to understand whether the maintainers consider this a
security concern or expected behaviour — and, if so, what the realistic attack surface is.

We are aware that EL/SpEL evaluation on this exact code path is an intended feature (it was
requested in #217, which references NacosUtils#readFromEnvironment and asks for expressions such as
dataId = "#{'server-' + systemEnvironment.servId}"). So expression evaluation itself is by design;
our question is about the capability of the evaluation context and the trust level of the input.

Where

nacos-spring-context/.../com/alibaba/nacos/spring/util/NacosUtils.java

public static String readFromEnvironment(String label, Environment environment) {
    String value = resolvePlaceholders(label, environment);          // resolves ${...}
    return StringUtils.hasText(value) ? evaluate(value, environment) : value;
}

public static String evaluate(String value, Environment environment) {
    Expression expression = parser.parseExpression(value, new TemplateParserContext()); // #{...}
    StandardEvaluationContext evaluationContext = new StandardEvaluationContext(environment);
    evaluationContext.addPropertyAccessor(new EnvironmentAccessor());
    return expression.getValue(evaluationContext, String.class);     // evaluated here
}

Because the context is a full StandardEvaluationContext, a value such as
#{T(java.lang.Runtime).getRuntime().exec('calc')} would also be evaluated (calc used only as a
harmless placeholder), i.e. the engine has full type/reflection access rather than just property
resolution against the Environment.

What we'd like to confirm

  1. Is this considered a vulnerability, or expected functionality? If the strings reaching
    evaluate(...) are only ever local, developer-authored config (annotation literals, application
    properties), the trust model may be "config author == app owner", in which case this is likely
    expected behaviour and can be closed.

  2. Can a Nacos config-center value reach this sink? Nacos is, by design, a remote configuration
    source whose content can be published/changed via the config center. If a value pulled from the
    Nacos config center (e.g. through @NacosValue / @NacosPropertySource / a config listener) can
    flow into readFromEnvironment / readFromBeanFactoryevaluate(...), then someone who can
    publish config (but is not otherwise authorized to run code on the app host) could achieve RCE.

    • Is that data-flow possible in supported usage?
    • If so, does that cross a privilege boundary you consider in scope?

    We could not fully trace the call sites that feed readFromEnvironment from the snapshot we have,
    which is the main reason we're asking rather than asserting.

If you consider hardening worthwhile (defence-in-depth)

Independent of the trust-model question, the evaluation could be narrowed to its apparent purpose
(placeholder/property resolution against the Environment) by using a restricted
SimpleEvaluationContext with only the needed property accessors, which disables T(...) type
references, constructors and arbitrary method calls while keeping the placeholder/expression feature
for property access. This would not change the behaviour requested in #217 for simple property
expressions, only remove the reflective code-execution capability.

Thanks for any clarification — happy to provide more detail, or to close this if it is intended
behaviour within the expected trust model.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions