Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

sandboxed-java-in-java-poc

A proof-of-concept showing how to sandbox a Java function and expose it as a standard java.lang.invoke.MethodHandle.

The pipeline: Java source → GraalVM WebImage → Wasm → Endive (JVM) → MethodHandle

┌─────────────────────────────────────────────────────┐
│ Host JVM                                            │
│                                                     │
│   MethodHandle sandboxedAdd = calculator.asMethodHandle();      │
│   int result = (int) sandboxedAdd.invoke(2, 3); // → 5         │
│                                                     │
│   ┌───────────────────────────────────────────────┐ │
│   │ Wasm Sandbox (Endive)                         │ │
│   │  • No filesystem access                       │ │
│   │  • No network access                          │ │
│   │  • stdout captured, not forwarded              │ │
│   │  • Host controls all imports                   │ │
│   │                                               │ │
│   │  Calculator.add(2, 3) → 5                     │ │
│   └───────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘

How it works

Guest module (guest/) — a plain Java class compiled to WebAssembly via GraalVM WebImage:

public class Calculator {
    public static int add(int a, int b) {
        return a + b;
    }
}

Host module (host/) — loads the .wasm module using Endive, AOT-compiles it to JVM bytecode, and wraps the sandboxed function as a MethodHandle:

var calculator = new SandboxedCalculator();
MethodHandle sandboxedAdd = calculator.asMethodHandle();

int result = (int) sandboxedAdd.invoke(2, 3); // 5

The guest code runs inside a Wasm sandbox with zero capabilities — no filesystem, no network, no direct I/O. The host explicitly provides every import the guest can call.

Building

Requires GraalVM 25.1 EA with WebImage support:

./setup-graalvm.sh
export JAVA_HOME="$(pwd)/.graalvm/graalvm-25.1.0-dev+10.1"
export PATH="$JAVA_HOME/bin:$PATH"

# Compile Java → Wasm
mvn package -pl guest -Pnative

# Build host (AOT-compiles the Wasm, generates typed interfaces)
mvn package -pl host -DskipTests

# Run
mvn exec:java -pl host -Dexec.mainClass=com.example.sandbox.host.Main

Output:

MethodHandle type: (int,int)int
sandboxedAdd.invoke(2, 3) = 5
sandboxedAdd.invoke(100, 200) = 300

WebImage limitations

GraalVM WebImage is designed for browser/Node.js targets, not for embedding individual functions. This creates friction for the sandboxing use case:

  • No individual function exports — WebImage only exposes main(String[]). @JS.Export exists but is not implemented yet. Arguments and results must be marshaled through string args and stdout capture.
  • Heavy host function surface — even a trivial guest requires ~27 host function stubs (JS interop, type conversion, I/O) because WebImage assumes a JavaScript host environment.
  • Single-use instances — WebImage calls System.exit() after main() returns, so each invocation requires a fresh Wasm instance.
  • Large binaries — the calculator .wasm is ~1.2 MB because it includes the full SubstrateVM runtime.

Kotlin has a better story

Kotlin/Wasm compiles to WasmGC and produces clean, embeddable modules with individual function exports. Several projects already provide ergonomic Wasm sandboxing for Kotlin:

  • Glueball — a Kotlin Multiplatform library for embedding WebAssembly modules with typed bindings
  • Wasmline — Kotlin Multiplatform framework for loading and calling WASI-compliant Wasm plugins, powered by Wasmtime

These can export individual @WasmExport functions with primitive signatures, avoiding the main() bottleneck and the host function ceremony entirely.

Project structure

├── guest/                          # The sandboxed Java function
│   ├── pom.xml                     # GraalVM WebImage compilation
│   └── src/.../Calculator.java     # public static int add(int, int)
├── host/                           # The JVM host
│   ├── pom.xml                     # Endive compiler plugin + moduleInterface
│   └── src/.../
│       ├── SandboxedCalculator.java    # MethodHandle wrapper (~50 lines)
│       ├── WebImageHostFunctions.java  # Host function stubs (~80 lines)
│       └── Main.java                   # Demo
├── setup-graalvm.sh
└── pom.xml

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages