The sandbox page shows what riz confines. This one draws the line the other way: what each layer protects, and exactly where the confinement stops. Every protection below maps to a test that runs in CI — and every gap is named, not glossed.
Native runtimes (Bun, Node.js, Python, Rust, Go) get resource ceilings and, on Linux, a
filesystem allowlist. They do not get a syscall or network
jail. Deny-by-default confinement is the runtime = "wasm" path. Read each row as
"what holds, and where it doesn't."
| Defense layer | Native bun·node·python·rust·go |
WASM runtime="wasm" |
Boundary / limit |
|---|---|---|---|
| OS process + kill-on-drop | ✓ yes | ✓ yes | Each handler is its own process group; the child is SIGKILLed with the host. |
| Always-on rlimits CORE=0 · NOFILE · FSIZE · NPROC |
✓ yes | ✓ yes | Resource / DoS ceilings — not a confinement boundary. |
| prctl pair PDEATHSIG · NO_NEW_PRIVS |
Linux only | Linux only | Blocks setuid/exec privilege escalation. A no-op on macOS/BSD. |
| Opt-in rlimits RLIMIT_AS · RLIMIT_CPU |
opt-in | opt-in | Per-function memory / CPU caps. Off unless configured. |
| Landlock FS allowlist | Linux ≥5.13 | Linux ≥5.13 | No filesystem confinement on macOS/BSD; best-effort below kernel 5.13. |
| WASI deny-by-default filesystem + network |
✗ no | ✓ yes | No fs, no sockets unless granted. Native code is not WASI-confined. |
| Capability broker host-held credentials |
✗ no | ✓ yes | Guest never opens a socket; the DSN never crosses the WASI boundary. |
| Guards in / out fail-closed policy .wasm |
✓ yes | ✓ yes | One policy module wraps every runtime identically; a policy that can't run denies. |
| Syscall filter seccomp-bpf |
✗ no | ✓ via WASI | Native code runs at the OS user's full syscall surface. riz ships no seccomp filter. |
| Network egress | ✗ no | ✓ deny-default | Native egress is unrestricted — control it with a network policy or firewall. |
runtime = "wasm". Native runtimes are for code you trust, hardened
against faults and resource abuse — not confined against a hostile author.
child_inherits_always_on_caps ·
child_with_allowlist_can_read_allowed_path_only ·
one_wasm_guard_protects_every_runtime — the profile, the Landlock allowlist, and
the cross-runtime guard, in CI.
A runtime = "wasm" request passes the WASI capability check, runs, then leaves
through the always-on host profile — wrapped on both sides by fail-closed guards. The walls
are real; so are their edges:
request ↓ guard_in fail-closed ↓ WASI capability check deny-by-default fs: no grant → denied net: no grant → denied ↓ your .wasm runs sub-ms spawn ↓ host safety profile always-on rlimits · PDEATHSIG · no-new-privs ↓ guard_out redact / block ↓ response
The assets riz protects: the host and other tenants' data, the network, and any
credentials it holds. The boundaries that protect them: the WASI line, the OS process
boundary, and the auth surface on /deploy and /_riz/*.
/deploy fails closed: with neither a deploy
key nor a CIDR allowlist configured, it refuses every request (503) rather than exposing a
hot-swap RCE. Credentials for a broker resource live host-side and never enter guest memory.
In scope for reports: sandbox / capability escapes, auth
bypass (JWT/JWKS authorizers, bearer-gated /_riz/*), static-serving path
traversal, the process safety profile, and POST /deploy.
Out of scope: misconfigurations riz already rejects at
startup, and non-HTTP/WS AWS event sources (out of project scope by design).
deploy_refuses_when_no_auth_configured ·
wasm_guest_brokers_pg_through_capability_grants — the fail-closed deploy gate and
the full broker chain (guest → host → Postgres, creds host-side), in CI.
Every push runs cargo-deny against deny.toml: RUSTSEC advisories, an
SPDX license allowlist, banned/wildcard crates, and registry provenance. A newly-published CVE
can fail CI with no code change — that's the point. The fix is a dependency bump; where no
fixed release exists, a dated, documented exception in
deny.toml, reviewed on its expiry.
cargo-deny in CI. Advisories with a fix are resolved by bumping — recent
examples: wasmtime-wasi (a WASI FilePerms bypass on the sandbox's own filesystem
boundary), anyhow, crossbeam-epoch.
A CycloneDX SBOM (riz.cdx.json) is generated each build and published as an
artifact, so a consumer can diff the exact dependency set that produced a release.
Release binaries carry keyless GitHub build-provenance attestations (SLSA, via Actions
OIDC — no signing keys held). Verify: gh attestation verify <file> --repo 24X7/riz.
Detached signatures, a curl … | sh installer that verifies before it runs,
and an external security review. Named here so the gap is visible, not implied away.
The request path has no reachable panic on runtime data, queues are bounded with backpressure, and bad input sheds one request rather than the fleet. Each line below is a fix with a named test.
Auth & edge. Reflected-origin credentialed CORS is rejected at config time; the JWKS authorizer is cached per issuer so a stream of invalid tokens can't amplify into an IdP fetch each; the authorizer returns an error on every hostile token instead of panicking the request task.
Supervision & ops. A config hot-swap rebuilds the pool so a concurrency change actually resizes admission; a readiness probe sheds traffic the instant a drain starts; and the metrics endpoint exposes saturation — utilization and load-shed counts, so overload shows up before requests start dropping. Off Linux, an unenforceable filesystem sandbox warns loudly instead of running silently unconfined.
validate_rejects_wildcard_origin_with_credentials ·
jwks_authorizer_cache_fetches_once_within_cooldown ·
authorizer_rejects_arbitrary_tokens_without_panic ·
hot_swap_resizes_concurrency ·
ready_when_serving_draining_after_shutdown_signal ·
metrics_emit_saturation_reliability_and_build_info ·
allowed_paths_sandbox_enforcement_matches_platform —
seven fixes, seven tests, in CI.
Please don't open a public issue for a security problem. Report via GitHub's
Security → "Report a vulnerability" (private advisory), or
email chris@riz.dev. Include impact, a minimal
riz.toml + handler to reproduce, and the riz version / OS / runtime. We aim to
acknowledge within 3 business days and coordinate disclosure
with you.