Skip to content
Advertisement

Security risks when evaluating user input as JavaScript in Java

I want to give the user the possibility of writing symbolic maths formulas which are later evaluated with certain values.

The user might – for example – want to enter some formula a * (b + 1) where a and b may be different upon each evaluation. My approach so far was using the built in JavaScript engine in Java but as I read through this tutorial on scripting, I realized that the engine is actually really powerful.

The formulas are stored in configuration files, so someone might send such a configuration file to another user, which would then be executed on their machine. Unfortunately I don’t know JavaScript, so I don’t know if the user could actually inject any seriously malicious code.

The formula above would be stored as a JavaScriptFormulaProcessor object like this:

JavaScriptFormulaProcessor processor =
        new JavaScriptFormulaProcessor("a * (b + 1)", "a", "b");

Initializing the engine:

public JavaScriptFormulaProcessor(String formula, String... variableNames) throws ScriptException {
    ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
    StringBuilder builder = new StringBuilder(variableNames[0]);
    for (int i = 1; i < variableNames.length; i++) {
        builder.append(", ").append(variableNames[i]);
    }
    String script = "function f("+builder.toString()+") { return "+formula+"}";
    engine.eval(script);
    invocable = (Invocable) engine;
}

Executing the function:

public void execute(Number[] functionInputs) throws ScriptException {
    try {
        Object result = invocable.invokeFunction("f", functionInputs);
        // process result..
    } catch (NoSuchMethodException e) {
        throw new RuntimeException(e); // should actually never be thrown..
    }
}

Does this code create an attack vector for my application? Bonus question: if yes, any better suggestions?

Advertisement

Answer

If formula is under the users’ control, then this code is extremely vulnerable because Java methods can be accessed and run from within the ScriptEngine.

See also this question: Why can you execute Java-Code from a JS-ScriptEngine eval(String)?

As an example, consider this formula:

String formula = "(java.lang.Runtime.getRuntime().exec('some-malicious-script'), a+b)";

Apart from calculating the sum, this script would run java.lang.Runtime.getRuntime().exec(). You can run any static Java method this way.

Advertisement