Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ci/platform-matrix.json
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@
{
"name": "Sandboxed execution",
"status": "caveated",
"notes": "Landlock, seccomp, network namespace isolation, no-new-privileges, privilege dropping, and process limits (nproc 512 at `scripts/lib/sandbox-rlimits.sh:8`) are tested and on by default. The `DANGEROUS_CAPS` list at `scripts/lib/sandbox-init.sh:275-286` drops cap_sys_admin, cap_sys_ptrace, cap_net_raw, cap_dac_override, cap_sys_chroot, cap_fsetid, cap_setfcap, cap_mknod, cap_audit_write, cap_net_bind_service with `capsh --drop` when CAP_SETPCAP is present. Limitation (active issue #3280): the fail-closed bounding-set gate is opt-in via `NEMOCLAW_REQUIRE_CAP_DROP=1`; the default is warn-and-continue so hosts without CAP_SETPCAP still boot, which means dangerous caps can remain in the bounding set on some hosts even though the effective set is empty."
"notes": "Landlock, seccomp, network namespace isolation, no-new-privileges, privilege dropping, and process limits (nproc 512 at `scripts/lib/sandbox-rlimits.sh:8`) are tested and on by default. Under full enforcement, OpenShell clears the child bounding set. OpenClaw and Hermes skip duplicate capability dropping only after observing five empty capability sets in the calling process. Other states retain the `DANGEROUS_CAPS` list and one `capsh` attempt in `scripts/lib/sandbox-init.sh`. Limitation (active issue #3280): `NEMOCLAW_REQUIRE_CAP_DROP=1` requires verification of the listed dangerous bounding capabilities; it does not require all five sets to be empty. Without strict mode, the fallback warns and continues when dangerous bounding capabilities remain or cannot be verified."
},
{
"name": "Routed inference",
Expand Down
13 changes: 8 additions & 5 deletions docs/deployment/sandbox-hardening.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,21 @@ Enforce both limits at the container runtime when that residual risk matters to

## Dropping Linux Capabilities

The NemoClaw entrypoint drops dangerous capabilities from the process bounding set before it starts agent services.
It removes `CAP_SYS_ADMIN`, `CAP_SYS_PTRACE`, `CAP_NET_RAW`, `CAP_DAC_OVERRIDE`, `CAP_SYS_CHROOT`, `CAP_FSETID`, `CAP_SETFCAP`, `CAP_MKNOD`, `CAP_AUDIT_WRITE`, and `CAP_NET_BIND_SERVICE`.
Under full enforcement, OpenShell clears the child bounding set before starting the entrypoint.
The entrypoint skips the duplicate drop only when its effective, permitted, inheritable, ambient, and bounding capability sets are present and empty.
Other states retain the legacy fallback, which can attempt `capsh` once when it is available and the process has `CAP_SETPCAP`.
The fallback removes `CAP_SYS_ADMIN`, `CAP_SYS_PTRACE`, `CAP_NET_RAW`, `CAP_DAC_OVERRIDE`, `CAP_SYS_CHROOT`, `CAP_FSETID`, `CAP_SETFCAP`, `CAP_MKNOD`, `CAP_AUDIT_WRITE`, and `CAP_NET_BIND_SERVICE`.
The managed images install `setpriv` from `util-linux` and require it for the switch from root to the `sandbox` and `gateway` users.
When `CAP_SETPCAP` is available, the same `setpriv` operation also removes the remaining privilege-separation capabilities from the child process bounding set.

The bounding-set drop is best effort: if `capsh` or `CAP_SETPCAP` is unavailable, the entrypoint logs a warning and still uses `setpriv` to change the user, group, and supplementary groups.
For root-to-user transitions, the extra bounding-set drop is best effort: if `capsh` or `CAP_SETPCAP` is unavailable, the entrypoint warns and uses `setpriv` without that drop.
When a root entrypoint must change identity, it fails closed if `setpriv` is missing instead of starting an agent service as root.

To make the drop fail-closed instead, set `NEMOCLAW_REQUIRE_CAP_DROP=1` in the entrypoint environment: the agent then refuses to start unless the agent process tree's bounding set is verified free of the dangerous capabilities.
Set `NEMOCLAW_REQUIRE_CAP_DROP=1` to refuse startup unless the entrypoint verifies that its bounding set is free of the listed dangerous capabilities.
This strict-mode gate checks the bounding set only; it does not require all five capability sets to be empty.
This is opt-in because many hosts cannot drop capabilities, including cloud VMs, Docker Desktop, and WSL environments without `CAP_SETPCAP`.

The check covers the agent process tree only.
This startup check does not inspect fresh exec or connect processes.

For defense-in-depth, also drop all Linux capabilities at the container runtime when you launch the image directly.
In the examples below, `nemoclaw-sandbox` is a placeholder for the sandbox image NemoClaw builds during onboarding; substitute the image tag your install produced, which you can find with `docker images`.
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/platform-support.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ Each row below is a launch-facing capability claim that NemoClaw makes in docs,
| Capability | Status | Notes |
|------------|--------|-------|
| Guided onboarding | Tested | Single-command interactive wizard (`$$nemoclaw onboard`) that walks the user through inference provider selection, credential setup, and sandbox creation or update. It opens the agent dashboard when the selected runtime provides one. Non-interactive mode is supported with `--non-interactive` and `NEMOCLAW_*` environment variables for CI and scripted installs. |
| Sandboxed execution | Tested with limitations | Landlock, seccomp, network namespace isolation, no-new-privileges, privilege dropping, and process limits (nproc 512 at `scripts/lib/sandbox-rlimits.sh:8`) are tested and on by default. The `DANGEROUS_CAPS` list at `scripts/lib/sandbox-init.sh:275-286` drops cap_sys_admin, cap_sys_ptrace, cap_net_raw, cap_dac_override, cap_sys_chroot, cap_fsetid, cap_setfcap, cap_mknod, cap_audit_write, cap_net_bind_service with `capsh --drop` when CAP_SETPCAP is present. Limitation (active issue #3280): the fail-closed bounding-set gate is opt-in via `NEMOCLAW_REQUIRE_CAP_DROP=1`; the default is warn-and-continue so hosts without CAP_SETPCAP still boot, which means dangerous caps can remain in the bounding set on some hosts even though the effective set is empty. |
| Sandboxed execution | Tested with limitations | Landlock, seccomp, network namespace isolation, no-new-privileges, privilege dropping, and process limits (nproc 512 at `scripts/lib/sandbox-rlimits.sh:8`) are tested and on by default. Under full enforcement, OpenShell clears the child bounding set. OpenClaw and Hermes skip duplicate capability dropping only after observing five empty capability sets in the calling process. Other states retain the `DANGEROUS_CAPS` list and one `capsh` attempt in `scripts/lib/sandbox-init.sh`. Limitation (active issue #3280): `NEMOCLAW_REQUIRE_CAP_DROP=1` requires verification of the listed dangerous bounding capabilities; it does not require all five sets to be empty. Without strict mode, the fallback warns and continues when dangerous bounding capabilities remain or cannot be verified. |
| Routed inference | Tested | Provider-routed model calls through the OpenShell gateway, transparent to the agent. The agent uses `inference.local` inside the sandbox; provider credentials stay on the host. Supports every entry in the Providers table. |
| Declarative network policy | Tested | YAML-defined egress with policy presets. Presets include `slack`, `discord`, `telegram`, `weather`, `openclaw-pricing`, `huggingface`, `npm`, `pypi`, `brew`, and others. Hot-reloadable at runtime with `$$nemoclaw <name> policy add`. |
| Snapshot and restore | Tested | Create, list, and restore named snapshots of sandbox state with the `$$nemoclaw <name> snapshot` subcommands (`create`, `list`, `restore`). Credential stripping is enforced on capture. Unsafe symlinks are rejected on restore. |
Expand Down
2 changes: 1 addition & 1 deletion docs/security/best-practices.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ The following patterns weaken security without providing meaningful benefit.
|---------|---------------|-------------------|
| Omitting `protocol: rest` on REST API endpoints without a compatibility reason | Endpoints without a `protocol` field use L4-only enforcement. The proxy allows the TCP stream through after checking host, port, and binary, but cannot see or filter individual HTTP requests. | Add `protocol: rest` with explicit `rules` to enable per-request method and path control on REST APIs. Use L4 pass-through only for documented cases such as npm/Yarn on Node 22, where the client requires a CONNECT tunnel that L7 inspection would break. |
| Adding endpoints to the baseline policy for one-off requests | Adding an endpoint to the baseline policy makes it permanently reachable across all sandbox instances. | Use operator approval. Approved endpoints persist within the sandbox instance but reset when you destroy and recreate the sandbox. |
| Relying solely on the entrypoint for capability drops | The entrypoint drops dangerous capabilities using `capsh`, but this is best-effort. If `capsh` is unavailable or `CAP_SETPCAP` is not in the bounding set, the container runs with the default capability set. | Pass `--cap-drop=ALL` at the container runtime level as defense-in-depth. |
| Relying solely on the entrypoint for capability drops | OpenShell owns child capability enforcement in full mode. Without strict mode, the legacy `capsh` fallback warns and continues when dangerous bounding capabilities remain or cannot be verified. | Keep OpenShell enforcement enabled. For direct container launches, pass `--cap-drop=ALL` as defense-in-depth. |
| Treating mutable agent config as an isolation boundary | The generated config tree contains model routing, channel settings, and runtime integration state (`/sandbox/.openclaw` for OpenClaw, `/sandbox/.hermes` for Hermes, `/sandbox/.deepagents` for Deep Agents). NemoClaw supports this state as mutable, so the agent can change it independently of host-managed policy and credential routing. | Treat OpenShell policy and credential providers as the enforcement boundary. Monitor agent-config drift and recreate the sandbox from trusted inputs after suspected compromise. |
| Adding inference provider hosts to the network policy for NemoClaw inference | Direct network access to an inference host bypasses credential isolation and usage tracking. | Use OpenShell inference routing instead of adding hosts like `api.openai.com` or `api.anthropic.com` to the network policy. Apply `claude-code` only when intentionally running the separate Claude Code CLI inside the sandbox. |
| Disabling device auth for remote deployments | Without device auth, any device on the network can connect to the gateway without pairing. Combined with a cloudflared tunnel, this makes the dashboard publicly accessible and unauthenticated. | Keep `NEMOCLAW_DISABLE_DEVICE_AUTH` at its default (`0`). Only set it to `1` for local headless or development environments. |
Expand Down
25 changes: 13 additions & 12 deletions docs/security/process-controls.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,32 @@ Refer to the [Process Controls](https://docs.nvidia.com/openshell/latest/securit

## Capability Drops

The entrypoint drops dangerous Linux capabilities from the bounding set at startup using `capsh`.
This limits what capabilities any child process (gateway, sandbox, agent) can ever acquire.
Under full enforcement, OpenShell clears the child bounding set before starting the agent.
The OpenClaw and Hermes entrypoints check their calling process's effective, permitted, inheritable, ambient, and bounding capability sets.
When all five sets are present and empty, startup skips the duplicate `capsh` drop.
Other states retain the legacy fallback, which can attempt `capsh` once when it is available and the process has `CAP_SETPCAP`.

The managed images install `setpriv` from `util-linux` and require it when the entrypoint switches from root to the `sandbox` and `gateway` users.
When `CAP_SETPCAP` is available, the same `setpriv` operation removes the remaining privilege-separation capabilities from the child process at the same time as the user change.

The initial entrypoint drop removes `cap_sys_admin`, `cap_sys_ptrace`, `cap_net_raw`, `cap_dac_override`, `cap_sys_chroot`, `cap_fsetid`, `cap_setfcap`, `cap_mknod`, `cap_audit_write`, and `cap_net_bind_service`.
The fallback drop removes `cap_sys_admin`, `cap_sys_ptrace`, `cap_net_raw`, `cap_dac_override`, `cap_sys_chroot`, `cap_fsetid`, `cap_setfcap`, `cap_mknod`, `cap_audit_write`, and `cap_net_bind_service`.
When the additional `setpriv` bounding-set drop runs, the child process also loses `cap_setuid`, `cap_setgid`, `cap_fowner`, `cap_chown`, and `cap_kill`.

The extra bounding-set capability drop is best effort.
If `capsh` is not available or `CAP_SETPCAP` is not in the bounding set, the entrypoint logs a warning and retains the runtime-provided bounding set.
The entrypoint still uses `setpriv` to change the user, group, and supplementary groups without the extra bounding-set drop.
For root-to-user transitions, the extra bounding-set capability drop is best effort.
If `capsh` or `CAP_SETPCAP` is unavailable, the root entrypoint logs a warning and uses `setpriv` without the extra bounding-set drop.

When a root entrypoint must change identity, it fails closed if `setpriv` is unavailable instead of starting an agent service as root.

To make the drop fail-closed instead of best-effort, set `NEMOCLAW_REQUIRE_CAP_DROP=1` in the entrypoint environment.
The agent then refuses to start unless it verifies that the agent process tree's bounding set is free of dangerous capabilities.
The agent then refuses to start unless the entrypoint verifies that its bounding set is free of the listed dangerous capabilities.
This strict-mode gate checks the bounding set only; it does not require all five capability sets to be empty.

It does not boot on a host whose bounding set still holds them, typically one that cannot perform the drop because `CAP_SETPCAP` or `capsh` is missing and the container runtime did not provide a clean bounding set.

This is opt-in because such hosts are common, including many cloud VMs, Docker Desktop, and WSL.
Leaving it unset preserves the best-effort default.

The check covers the agent process tree only.
The container runtime spawns a `$$nemoclaw connect` shell outside that tree, so the check does not affect it (tracked in [NVIDIA/OpenShell#1452](https://github.com/NVIDIA/OpenShell/issues/1452)).
This startup check does not inspect fresh exec or connect processes.

<AgentOnly variant="openclaw">
For additional protection, pass `--cap-drop=ALL` with `docker run` or Compose.
Expand All @@ -49,9 +50,9 @@ Refer to [Review Sandbox Hardening](../../manage-sandboxes/configure-sandboxes/r

| Aspect | Detail |
|---|---|
| Default | The entrypoint drops dangerous capabilities at startup using `capsh`, then requires `setpriv` for user step-down. When `CAP_SETPCAP` is unavailable, the user step-down continues without the extra privilege-separation bounding-set drop and logs a warning. |
| What you can change | When launching with `docker run` directly, pass `--cap-drop=ALL --cap-add=NET_BIND_SERVICE` for stricter enforcement. In the standard NemoClaw onboarding flow, the entrypoint handles capability dropping automatically. |
| Risk if relaxed | `CAP_SYS_ADMIN` and `CAP_SYS_PTRACE` expand kernel and process attack surface. `CAP_NET_RAW` allows raw socket access for network sniffing. `CAP_DAC_OVERRIDE` bypasses filesystem permission checks. If `capsh` cannot run or `CAP_SETPCAP` is unavailable, the container retains more of the runtime-provided capability set. |
| Default | OpenShell full enforcement clears the child bounding set. OpenClaw and Hermes skip the duplicate drop only after observing five empty capability sets. Root-to-user transitions still require `setpriv`. |
| What you can change | When launching with `docker run` directly, pass `--cap-drop=ALL --cap-add=NET_BIND_SERVICE` for stricter enforcement. Set `NEMOCLAW_REQUIRE_CAP_DROP=1` to require verification of the dangerous bounding capabilities. |
| Risk if relaxed | `CAP_SYS_ADMIN` and `CAP_SYS_PTRACE` expand kernel and process attack surface. `CAP_NET_RAW` allows raw socket access for network sniffing. `CAP_DAC_OVERRIDE` bypasses filesystem permission checks. Without strict mode, the fallback warns and continues when dangerous bounding capabilities remain or cannot be verified. |
| Recommendation | Run on an image that includes `capsh` and `setpriv` (NemoClaw-managed images include them). For defense-in-depth, also pass `--cap-drop=ALL` at the container runtime level. |

<AgentOnly variant="openclaw">
Expand Down
Loading
Loading