YuleYule
Changelogs

Process Sandbox

Untrusted binary data deserves a cage. Job Objects and AppContainer.

Process Sandbox — Job Objects and Guard Rails

The inference engine loads untrusted binary data (model files) and executes arithmetic on it. If there's a bug in the dequant path, a malformed GGUF, or a compromised model, the process has full access to the host system. Time to put the first wall up.


Windows Job Object Sandbox

When yule serve starts, the process assigns itself to a Windows Job Object with these restrictions:

  • Memory limit — 32GB default. Prevents a malicious model from exhausting system RAM.
  • No child processesJOB_OBJECT_LIMIT_ACTIVE_PROCESS set to 1. The inference process can't fork, exec, or spawn helpers.
  • Kill-on-close — if the parent handle closes (crash, kill), Windows terminates the process automatically.
  • UI restrictions — no clipboard read/write, can't create desktops, can't change display settings, can't register global atoms.

The sandbox is applied via AssignProcessToJobObject using windows-sys FFI bindings — no hand-rolled extern blocks. I initially wrote extern "system" { fn AssignProcessToJobObject(...); } — it worked but was fragile. windows-sys provides correct type definitions, handles the ABI correctly, and is maintained by Microsoft. One dependency swap, zero behavior change.


RAII and Policy

SandboxGuard holds the Job Object handle and calls CloseHandle on drop. If the guard drops (scope exit, panic, process shutdown), the Job Object gets cleaned up. Combined with kill-on-close, this means no orphan processes.

SandboxPolicy is a declarative struct describing what to restrict: filesystem paths, network ports, GPU devices, resource limits. Phase A only enforces resource limits via the Job Object. Filesystem, network, and GPU isolation need the broker-target architecture in Phase B.


CLI Integration

yule serve applies the sandbox by default. --no-sandbox disables it. The flag is intentionally negative — sandboxing should be the default, not something you opt into.

The server logs whether sandboxing is active at startup, and includes sandbox status in every API response's integrity block.


Cross-Platform

Linux and macOS implementations return proper errors (UnsupportedPlatform) instead of todo!(). This means yule serve works on all platforms — it just warns that sandboxing is unavailable rather than panicking.


Notes

In-process Job Object instead of broker-target because broker-target needs IPC, message serialization, handle passing, and cross-platform process spawning. Job Object gives real protection now with minimal code. Broker-target is Phase B.

Clipboard access is blocked because it's a real exfiltration vector — a compromised process could read passwords, SSH keys, API tokens. Costs nothing to block.


What's Left (Phase B)

Phase A is a speed bump, not a wall. The process can still read arbitrary files, make network connections, and interact with the GPU driver. Real isolation needs:

  • Broker-target architecture with separate processes and IPC
  • Seccomp-BPF (Linux) — syscall allowlist
  • AppContainer (Windows) — integrity level isolation
  • Seatbelt (macOS) — kernel-level sandbox profiles
  • GPU ioctl allowlist — only memory management and command submission

On this page