GraalVM Security Guide

This security guide provides developers and embedders with information on the security model and features of GraalVM, such that they can build a secure application on top of it. It assumes that readers are familiar with the GraalVM architecture. This guide does not replace but rather supplements the Java security documentation with aspects unique to GraalVM. It also provides security researchers with information on GraalVM’s security model.

Security Model #

GraalVM is a shared runtime. It accepts instructions in a higher-level programming language (or an intermediate representation thereof) as input, which is executed later. Developers that implement security controls for their applications (such as access control) in code that is being run by GraalVM can rely on the correct execution of instructions. Incorrect execution of security-critical code running on top of GraalVM that allows to bypass such a security control is regarded a security vulnerability.

Debug features should only be used in a trusted environment as they provide privileged access to an application, allowing to inspect and change its state and behavior. They may further open network sockets to allow debug clients to connect.

We appreciate reports of bugs that break the security model via the process outlined in the Reporting Vulnerabilities guide.

Language Implementation Framework #

Using the Language Implementation Framework, interpreters for guest languages can be implemented to execute guest applications written in languages such as Javascript, Python, Ruby, R or WebAssembly (Wasm) on top of GraalVM. Whereas the execution context for these applications can be created with restricted privileges, this mechanism is only fully supported for Javascript and should not be used to execute untrusted code.

For every language implemented with the Language Implementation Framework, and shipped with GraalVM, a launcher, e.g., interactive shell, is provided. These launchers behave in the same way and come with the same security guarantees as their “original” counterparts. The languages implemented with the Language Implementation Framework are henceforth referenced as guests languages.

Sharing Execution Engines #

Application developers may choose to share execution engines among execution contexts for performance reasons. While the context holds the state of the executed code, the engine holds the code itself. Sharing of an execution engine among multiple contexts needs to be set up explicitly and can increase performance in scenarios where a number of contexts execute the same code. In scenarios where contexts that share an execution engine for common code also execute sensitive (i.e., private) code, the corresponding source objects can opt out from code sharing with:

Source.newBuilder(…).cached(false).build()

ScriptEngine Compatibility #

For reasons of backward compatibility, certain guest languages also support Java’s ScriptEngine interface. For example, this allows GraalVM JavaScript to be used as a drop-in replacement for Nashorn. However, to maintain compatibility, the Nashorn GraalVM JavaScript ScriptEngine interface will create a context with all privileges granted to the script and should be used with extreme caution and only for trusted code.

Native Image #

The native image builder generates a snapshot of an application after startup and bundles it in a binary executable.

By default, the native image builder executes the static initializers of classes at build time and persists the state in the native image heap. This means that any information that is obtained or computed in static initializers becomes part of the native image executable. This can lead to unintentionally including properties of the build environment, such as environment variables in the image heap. This can either result in sensitive data ending up in the snapshot or fixing initialization data that is supposed to be obtained at startup, such as random number seeds.

Developers can request static initializers that process sensitive information to be instead executed at runtime by either specifying the --initialize-at-run-time CLI parameter when building a native image, or making use of the RuntimeClassInitialization API.

In addition, developers can run the native image builder in a dedicated environment, such as a container, that does not contain any sensitive information in the first place.

Security Manager and Untrusted Code #

The OpenJDK vulnerability group strongly discourages to running untrusted code under a security manager. This also applies to GraalVM, which does not support untrusted code execution in Java. While GraalVM’s ability to restrict the execution of guest language applications to a certain extent is not dependent on a security manager, it is not suited to be used as a sandbox for running untrusted code.

Native Image does not support a security manager in general. Attempting to set a security manager will trigger a runtime error.

The Language Implementation Framework needs to be invoked with all permissions to make full use of its functionality - it provides its own controls to manage resources.

If untrusted and potentially malicious code is to be executed, we recommend GraalVM customers who have an immediate requirement to execute untrusted and potentially adversarial code, adopt the appropriate isolation primitives to ensure the confidentiality and integrity of their application data.