Run untrusted Python and JavaScript safely. No Docker, no VMs, just WebAssembly.
You need to execute user-submitted or AI-generated code. Your options:
- Docker: Requires daemon, orchestration, Linux features. Overkill for running a Python snippet.
- Firecracker/gVisor: Linux-only, complex setup, operational overhead.
- Native execution: Dangerous. One
os.system('rm -rf /')and you're done.
- Code execution platforms - LeetCode clones, coding interviews, online judges
- LLM tool execution - Run AI-generated code without risking your infrastructure
- Plugin systems - Let users extend your app with custom scripts
- Educational platforms - Safe code playgrounds for students
- High-performance computing - WASM adds overhead; use native execution if you trust the code
- NumPy/Pandas workloads - C extensions don't work in WASI; pure Python only
- Long-running processes - Designed for short scripts, not daemons or servers
- Multi-threaded code - WASI doesn't support threads
Performance: WASM interpretation adds ~2-10x overhead vs native. Cold starts are slow (~500ms Python, ~100ms JS). We mitigate with disk caching and session reuse.
WASI constraints: No threads, no raw sockets, no FFI. Python's multiprocessing, threading, socket, ssl modules are blocked. C extensions (numpy, pandas) won't load.
Abstraction layer: http, fs, kv modules are wrappers over host functions, not real stdlib. They're injected into the runtime and call back to Go. This means:
- No
requestslibrary (use built-inhttpmodule instead) - No direct filesystem access (only mounted paths via
fs) - Behavior may differ slightly from native equivalents
- Bidirectional host-guest protocol - Sandboxed code calls Go functions via
call(), Go receives structured responses (docs) - Extensible - Register custom Go functions callable from sandbox via
Registry.Register()(docs) - Async batching - Concurrent host calls with
asyncio.gather()/Promise.all()batched into single round-trip (docs) - Capability-based security - Zero permissions by default, opt-in HTTP/filesystem/KV per-session (docs)
- Session state - Variables persist across executions, define functions once and reuse (docs)
- Built-in modules -
http,fs,kvavailable in sandbox without imports when enabled (docs) - Python packages - Pre-install via CLI or allow runtime
install_pkg()from sandboxed code (docs)
By default, sandboxed code has zero capabilities:
| Capability | Default | Enable With |
|---|---|---|
| Filesystem | Blocked | WithMount() |
| HTTP | Blocked | WithAllowedHosts() |
| KV Store | Blocked | WithKV() |
| Host Functions | Blocked | Registry.Register() |
# CLI
curl -fsSL https://raw.githubusercontent.com/caffeineduck/goru/main/install.sh | bash
# Go library
go get github.com/caffeineduck/gorugoru script.py # Run file
goru --lang python -c 'print(1+1)' # Inline code
echo 'print(1+1)' | goru -l python # Pipe code via stdin
echo 'console.log(1+1)' | goru -l js # Works with JavaScript too
goru repl --lang python # Interactive REPL
goru --help # Full optionsexec, _ := executor.New(hostfunc.NewRegistry())
defer exec.Close()
session, _ := exec.NewSession(python.New(),
executor.WithSessionAllowedHosts([]string{"api.example.com"}),
executor.WithSessionMount("/data", "./input", hostfunc.MountReadOnly),
executor.WithSessionKV(),
)
defer session.Close()
session.Run(ctx, `x = 42`)
session.Run(ctx, `resp = http.get("https://api.example.com/data")`)
result := session.Run(ctx, `print(x, resp["status"])`)Full API: pkg.go.dev/github.com/caffeineduck/goru
- Sandbox API - APIs for Python/JavaScript code running in the sandbox
- Go API - Go embedding documentation on pkg.go.dev
MIT