Interesting!! I've been playing around with QuickJS lately and uses Elixir at work.
I'm interested to hear about your sandboxing approach running untrusted JS code. So you are setting an memory/reduction limit to the process which 100% is a good idea. What other defense-in-depth strategies are you using? possible support for seccomp in the future?
Layers right now:
— Memory limits: JS_SetMemoryLimit per-runtime (256 MB default), JS_SetContextMemoryLimit per-context. Exceeding → JS exception, not a crash.
— Execution limits: interrupt handler checks a nanosecond deadline every opcode. For contexts, max_reductions caps JS operations independently of wall-clock time.
— API surface: apis: false gives bare QuickJS — no fetch, no fs, no DOM, no I/O. You control exactly which Elixir functions JS can call via the handlers map. JS cannot call arbitrary Elixir code.
— Conversion limits: max_convert_depth (32) and max_convert_nodes (10k) prevent pathological objects from blowing up during JS↔BEAM conversion.
— Process isolation: separate OS thread, separate QuickJS heap per runtime.
No seccomp — QuickJS runs in-process so seccomp would restrict the entire BEAM. The sandbox boundary is QuickJS-NG's memory-safe interpreter (no JIT, no raw pointer access from JS) plus the API surface control above.