import javax.script.*; /* This example demonstrates possible leakage of Nashorn scopes and the incorrect scope being used when executing a function defined in one scope, from another scope. */ public class LeakTest { public static void main(String[] args) { new LeakTest().run(); } /* script1 contains a function which simply sets a global, and then immediately logs out the type of the global to system.out I would expect it to log "typeof global is number" Instead it logs "typeof global is undefined" script1 runs inside its own scope - this is basically how commonJS modules would be run -they are allowed to set globals but these won't be visible to other scopes that call it. */ private String script1 = "function foo() { \n" + " _someglobal = 123; \n" + " java.lang.System.out.println('typeof global is ' + typeof _someglobal); \n" + " // Now set another global \n" + " _someotherglobal = 456; \n" + "} \n" + "_javaobject.setFunction(foo);"; /* script2 simply calls the function foo() which we export by setting its value through a Java object it then tries to display the value of _someotherglobal which was defined in another scope, and succeeds! */ private String script2 = "foo(); \n" + "java.lang.System.out.println('someotherglobal is ' + _someotherglobal)"; private void run() { try { ScriptEngineManager factory = new ScriptEngineManager(); ScriptEngine engine = factory.getEngineByName("nashorn"); // Run script1 in it's own scope ScriptContext ctx = new SimpleScriptContext(); Bindings bindings = engine.createBindings(); bindings.put("_javaobject", this); ctx.setBindings(bindings, ScriptContext.ENGINE_SCOPE); engine.eval(script1, ctx); // Run script2 in it's own scope bindings = engine.createBindings(); bindings.put("foo", function); ctx = new SimpleScriptContext(); ctx.setBindings(bindings, ScriptContext.ENGINE_SCOPE); engine.eval(script2, ctx); } catch (Exception e) { e.printStackTrace(); } } private Object function; // This allows us to pass an JavaScript object from one scope to another public void setFunction(Object function) { this.function = function; } }