Search code examples
javascriptjavasecuritycode-injectionsymbolic-math

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?


Solution

  • 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.