You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Added Linux-only nsjail-based sandboxing for worker processes, including CLI support, configuration, and testing.
* Added validation for `Content-Length` in `headerPrefixPipe` and tests for oversized and negative values
* Enhanced `build.yml` to compile and install nsjail from source instead of using system package.
* Switched nsjail mode from "once" to "exec" for direct command execution with inherited stdio.
* Replaced `--time_limit` with `--rlimit_cpu` in nsjail arguments to ensure compatibility in containers without cgroupv2.
* Updated sandbox test to replace `--time_limit` with `--rlimit_cpu` and adjusted workflow to run integration tests with elevated permissions.
Shimmy can wrap each worker process in an [nsjail](https://github.com/google/nsjail) sandbox to safely execute arbitrary, untrusted code. The sandbox provides:
251
+
252
+
-**Filesystem confinement** — the worker can only access explicitly bind-mounted paths
253
+
-**Resource limits** — CPU time, memory, and file descriptor caps
254
+
-**Network isolation** — optional; disables all outbound connections
255
+
-**Unprivileged UID** — worker runs as `nobody` (uid 65534) inside the jail
256
+
257
+
Sandboxing requires Linux and the `nsjail` binary. The Docker image built from the project's `Dockerfile` includes nsjail at `/usr/sbin/nsjail`. On the host, install it with `sudo apt install nsjail` (Ubuntu 22.04+) or build from source.
258
+
259
+
Enable sandboxing with `--sandbox` and configure it with the flags below:
A typical invocation for an untrusted Python worker:
275
+
276
+
```shell
277
+
shimmy -c python3 -a evaluation.py \
278
+
--sandbox \
279
+
--sandbox-ro-bind /usr \
280
+
--sandbox-ro-bind /lib \
281
+
--sandbox-ro-bind /lib64 \
282
+
--sandbox-rw-bind /tmp/shimmy \
283
+
--sandbox-cpu-time 30 \
284
+
--sandbox-memory-mb 256 \
285
+
--sandbox-disable-network
286
+
```
287
+
288
+
> **Note:** nsjail requires either root or user namespace support. In Docker, pass `--privileged` or grant `CAP_SYS_ADMIN`. In Kubernetes, configure the pod's security context accordingly.
289
+
290
+
#### Testing sandboxing locally
291
+
292
+
The sandbox integration tests verify actual security properties — filesystem isolation, CPU limits, network isolation, and stdio passthrough. They skip automatically if `nsjail` is not available.
293
+
294
+
**On Linux with nsjail installed:**
295
+
296
+
```shell
297
+
go test -v -run 'TestSandboxedWorker' ./internal/execution/worker/...
298
+
```
299
+
300
+
**On macOS (or any platform) via Docker or Podman:**
301
+
302
+
```shell
303
+
make test-sandbox # Docker (default)
304
+
CONTAINER_ENGINE=podman make test-sandbox # Podman
305
+
```
306
+
307
+
This builds the `nsjail-builder` Dockerfile stage (the same nsjail used in production) and runs the tests inside a privileged container. Rootless Podman works fine: `--privileged` grants all capabilities within the user namespace, which is sufficient for nsjail to create its own sub-namespaces.
308
+
309
+
To manually verify isolation, run the Docker image with a sandboxed worker that attempts to read a protected file:
310
+
311
+
```shell
312
+
docker run --rm --privileged \
313
+
-e FUNCTION_COMMAND=/bin/sh \
314
+
-e FUNCTION_ARGS="-c,cat /etc/shadow" \
315
+
-e SANDBOX_ENABLED=true \
316
+
-e SANDBOX_RO_BINDS="/usr:/bin:/lib:/lib64" \
317
+
ghcr.io/lambda-feedback/shimmy serve
318
+
```
319
+
320
+
The worker should exit with a non-zero code because `/etc` is not mounted inside the sandbox.
0 commit comments