Sandbox Commands¶
Experimental
The OS-level sandbox is experimental. See Configuration Reference for sandbox settings.
Inspect sandbox configuration, platform capabilities, and run isolation smoke tests.
OS-level Sandbox vs P2P Sandbox
lango sandbox manages OS-level process isolation (macOS Seatbelt; Linux bubblewrap when the bwrap binary is installed) for local tool execution. This is distinct from lango p2p sandbox which manages container-based isolation for remote P2P tool execution.
Linux requirement: install the bubblewrap package (apt install bubblewrap, dnf install bubblewrap, or equivalent). On startup, lango runs a two-phase namespace smoke probe (base + network) that actually invokes bwrap against /bin/true, so hosts where bwrap --version succeeds but kernel namespace creation is blocked (e.g. kernel.unprivileged_userns_clone=0, AppArmor lockdown) are reported unavailable with an actionable reason instead of failing at first command execution. When only the network isolation probe fails, base sandboxing still works and MCP stdio servers (which allow host network) continue to run; only policies requiring --unshare-net are rejected. The native Landlock+seccomp backend is planned but not yet implemented; selecting backend=native returns an unavailable isolator with a clear reason.
Path semantics. Sandbox policy paths (deny baselines, allowedWritePaths) pass through a shared normalization pipeline across all backends: sanitize → absolute → glob expand → symlink resolve. File-level deny is supported via --ro-bind /dev/null <file> so individual secret files and linked-worktree .git pointers can be denied. Symlinked targets are resolved to their real path before emission (symlink escape closed). Glob patterns like ~/.lango/*.db expand at policy construction time; unmatched patterns silently skip and invalid patterns fail loudly at startup.
lango sandbox status¶
Show sandbox configuration, active isolation backend, platform capabilities, backend availability, and recent sandbox decisions from the audit log.
The output includes:
- Sandbox Configuration: enabled, fail-closed mode, selected backend, network mode
- Active Isolation: which isolator is running and why (if unavailable). When the bwrap network isolation probe fails but base sandboxing works, an additional
Network Iso: unavailable (reason)line surfaces the partial degradation — NetworkAllow policies (e.g. MCP) continue to work while NetworkDeny policies are rejected at Apply time. - Platform Capabilities: kernel-level primitives (Seatbelt, Landlock, seccomp)
- Backend Availability: status of each isolation backend (seatbelt, bwrap, native)
- Recent Sandbox Decisions: the last 10 apply / skip / reject / exclude events from the audit log (graceful — omitted if the audit DB is unavailable)
lango sandbox status [flags]
| Flag | Type | Description |
|---|---|---|
--output |
string |
Output format: table (default), json, or plain |
--session |
string |
Filter Recent Sandbox Decisions by session key prefix (default: show global last 10) |
Output formats¶
The default table format preserves the multi-section operator report. Use
json for automation and health checks, or plain for shell-friendly key-value
lines without table section headers.
lango sandbox status --output json
JSON output fields:
| Field | Type | Description |
|---|---|---|
configuration |
object | Sandbox enabled state, fail mode, selected backend label, network mode, workspace, and explicit opt-out state |
active_isolation |
object | Active isolator name, availability, unavailable reason, and partial network-isolation degradation when detected |
platform_capabilities |
object | Platform, kernel, Seatbelt, Landlock, and seccomp probe status |
backend_availability |
array | One row per platform backend candidate with name, mode, availability, and reason |
recent_decisions |
array | Recent sandbox decision audit rows when audit storage is available; empty when unavailable |
warnings |
object | Platform-specific warning booleans such as Linux allowedNetworkIPs non-enforcement |
Invalid output formats fail before config or bootstrap loading, so wrappers can validate command usage without triggering passphrase prompts.
Recent Sandbox Decisions¶
Each row shows the timestamp, an 8-character session-key prefix in brackets, the decision verdict, the backend that produced it (or - for non-applied verdicts), and the command target. When a reason or pattern is recorded, it appears in parentheses at the end.
Recent Sandbox Decisions (global, last 10):
2026-04-07 15:23:01 [a3f1abcd] applied bwrap git status
2026-04-07 15:22:55 [a3f1abcd] excluded - docker run -it ubuntu (pattern: docker)
2026-04-07 15:22:30 [b8c2efgh] skipped - go build (no isolator configured)
2026-04-07 15:22:00 [--------] applied seatbelt knowledge-search-server
The session key column shows -------- when the audit row has no session key (this happens for MCP server startup events, which are process-level rather than session-bound).
Excluded commands and the bypass audit¶
sandbox.excludedCommands lets you list command basenames that bypass the sandbox entirely (git, docker, etc.). Matching is performed against the basename of the user command's first whitespace-separated token, so chained commands like cd /tmp && git status do NOT trigger a bypass — only direct invocations like git status or /usr/bin/git push. Every excluded execution is recorded in the audit log with decision=excluded and the matched pattern, and is visible in this Recent Sandbox Decisions section.
Fail-open warning¶
When sandbox.failClosed=false (default) and the sandbox cannot be applied at runtime, lango proceeds without isolation but prints a one-shot stderr warning the first time a fallback occurs in the process:
lango: WARNING — sandbox fallback active (reason: ...); commands run unsandboxed
The warning fires at most once per process to avoid noise during long-running sessions; the full per-command audit trail is in this lango sandbox status section instead. The stderr warning path is exercised under test through a seam-aware writer so the one-shot contract stays deterministic.
lango sandbox test¶
Run OS sandbox smoke tests to verify isolation is working correctly. The test
honors the configured sandbox.backend: when set to none it short-circuits
with an explanatory message; when the configured backend is unavailable it
prints the reason and exits successfully without running the cases.
The test runs four cases against the active isolator:
- Write restriction (deny /etc) — invokes
/usr/bin/touch /etc/lango-sandbox-test. Must fail (sandbox denies writes outside the policy's WritePaths). - Read permission (allow system file) — reads
/etc/hosts(macOS) or/etc/hostname(Linux). Must succeed (ReadOnlyGlobal: trueallows reading any path). - Workspace write (allow tmp dir) — creates an
os.MkdirTempdirectory, adds it to the policy's WritePaths, and touches a file inside. Must succeed. - Network deny (loopback unreachable) — opens an ephemeral
127.0.0.1:0listener in the parent process and re-invokes the lango binary as a sandboxed child via the hidden_probe-net <addr>subcommand, which callsnet.DialTimeout. Must fail (sandbox blocks the connect, even to loopback).
The network test uses no external tools (nc/curl/bash//dev/tcp) so it
runs in minimal Docker images. Stdout/stderr are silenced via io.Discard in
the parent rather than shell redirection so that the sandbox's (deny default)
base on /dev/null cannot cause false negatives.
lango sandbox test