diff --git a/docs/changelog/2026-08-06.mdx b/docs/changelog/2026-08-06.mdx index ff3c8c82dd7..8546b0f3ab8 100644 --- a/docs/changelog/2026-08-06.mdx +++ b/docs/changelog/2026-08-06.mdx @@ -13,6 +13,9 @@ It also improves Hermes configuration safety, MCP diagnostics, credential isolat NemoClaw acquires and verifies the exact GGUF through the shared Hugging Face cache, publishes an authenticated loopback runtime, and uses owner, receipt, and journal state for onboarding, status, doctor, recovery, destroy, and uninstall. This path remains experimental and does not establish a supported agent, model, and runtime tuple until its protected qualification and activation gates pass. For more information, refer to [Choose a Local Inference Server](/user-guide/openclaw/inference/local-inference/choose-local-inference-server), the [NemoClaw CLI Commands Reference](/user-guide/openclaw/reference/commands), and [Understand Host Files and State](/user-guide/openclaw/reference/host-files-and-state). +- DGX Spark users can now select an opt-in fixed vLLM serving profile through the hosted installer or the CLI. + `profiles list` reports catalog entries and their host compatibility without changing resources, while `onboard --profile` records the exact catalog, recipe, and runtime provenance and rejects silent definition drift during resume. + For more information, refer to [Choose a Local Inference Server](/user-guide/openclaw/inference/local-inference/choose-local-inference-server), [Set Up vLLM](/user-guide/openclaw/inference/local-inference/set-up-vllm), and the [NemoClaw CLI Commands Reference](/user-guide/openclaw/reference/commands). - Custom inference endpoints, MCP servers, and custom policy presets can now opt in to explicitly trusted private hosts. NemoClaw keeps exact host allowlists, pins generated `allowed_ips`, preserves those pins across restart and rebuild, and applies configured certificate authority trust without widening the endpoint policy. For more information, refer to [Meet Custom Endpoint Security Requirements](/user-guide/openclaw/inference/custom-endpoints/custom-endpoint-security), [Create Custom Policy Presets](/user-guide/openclaw/network-policy/configure-policies/create-custom-policy-presets), and [Configure Corporate CA Trust](/user-guide/openclaw/security/configure-corporate-ca-trust). @@ -25,6 +28,10 @@ It also improves Hermes configuration safety, MCP diagnostics, credential isolat - Gateway and sandbox recovery now waits for the managed gateway lease, resumes journaled rebuild recreation, and applies compatibility decisions before rejecting a restored sandbox as not ready. Malformed sandbox registry data fails closed, gateways that never served receive bounded boot-grace recovery, and registry repair remains scoped to the target gateway. For more information, refer to [Understand Gateway Lifecycle Control](/user-guide/openclaw/manage-sandboxes/configure-sandboxes/understand-gateway-lifecycle-control), [Recover and Rebuild Sandboxes](/user-guide/openclaw/manage-sandboxes/operate-sandboxes/recover-and-rebuild-sandboxes), and [Troubleshooting](/user-guide/openclaw/reference/troubleshooting). +- Portable experimental-profile recovery can now restart a receipt-owned user-local Ollama executable after a semantic `/api/tags` health check. + When an unhealthy API requires a user-local start, recovery requires a valid ownership receipt or explicit re-enrollment for a pre-receipt installation. + It rejects symbolic links, refuses to launch a duplicate Ollama process, does not take over a system service or unrelated user-managed daemon, and verifies both the authenticated proxy and the sandbox `inference.local` route before reporting success. + For more information, refer to [Set Up Ollama](/user-guide/openclaw/inference/local-inference/set-up-ollama) and [Recover and Rebuild Sandboxes](/user-guide/openclaw/manage-sandboxes/operate-sandboxes/recover-and-rebuild-sandboxes). - Scoped uninstall now deletes the sandbox before removing its unit and preserves the gateway and unit when sandbox deletion fails, leaving a retryable state instead of partial teardown. Desktop metadata no longer blocks uninstall when the managed runtime state is otherwise valid. For more information, refer to [Uninstall NemoClaw](/user-guide/openclaw/manage-sandboxes/operate-sandboxes/uninstall-nemoclaw) and the [NemoClaw CLI Commands Reference](/user-guide/openclaw/reference/commands). diff --git a/docs/index.yml b/docs/index.yml index 8394439c30f..58497a9f7e6 100644 --- a/docs/index.yml +++ b/docs/index.yml @@ -341,6 +341,18 @@ navigation: - page: "Security Best Practices" path: _build/agent-variants/security/best-practices.openclaw.generated.mdx slug: best-practices + - section: "Security Controls" + slug: security-controls + contents: + - page: "Filesystem Controls" + path: _build/agent-variants/security/filesystem-controls.openclaw.generated.mdx + slug: filesystem-controls + - page: "Process Controls" + path: _build/agent-variants/security/process-controls.openclaw.generated.mdx + slug: process-controls + - page: "Gateway and Secret Controls" + path: _build/agent-variants/security/gateway-authentication-controls.openclaw.generated.mdx + slug: gateway-authentication-controls - page: "Configure Corporate CA Trust" path: _build/agent-variants/security/configure-corporate-ca-trust.openclaw.generated.mdx slug: configure-corporate-ca-trust @@ -681,6 +693,18 @@ navigation: - page: "Security Best Practices" path: _build/agent-variants/security/best-practices.deepagents.generated.mdx slug: best-practices + - section: "Security Controls" + slug: security-controls + contents: + - page: "Filesystem Controls" + path: _build/agent-variants/security/filesystem-controls.deepagents.generated.mdx + slug: filesystem-controls + - page: "Process Controls" + path: _build/agent-variants/security/process-controls.deepagents.generated.mdx + slug: process-controls + - page: "Gateway and Secret Controls" + path: _build/agent-variants/security/gateway-authentication-controls.deepagents.generated.mdx + slug: gateway-authentication-controls - page: "Configure Corporate CA Trust" path: _build/agent-variants/security/configure-corporate-ca-trust.deepagents.generated.mdx slug: configure-corporate-ca-trust @@ -1060,6 +1084,18 @@ navigation: - page: "Security Best Practices" path: _build/agent-variants/security/best-practices.hermes.generated.mdx slug: best-practices + - section: "Security Controls" + slug: security-controls + contents: + - page: "Filesystem Controls" + path: _build/agent-variants/security/filesystem-controls.hermes.generated.mdx + slug: filesystem-controls + - page: "Process Controls" + path: _build/agent-variants/security/process-controls.hermes.generated.mdx + slug: process-controls + - page: "Gateway and Secret Controls" + path: _build/agent-variants/security/gateway-authentication-controls.hermes.generated.mdx + slug: gateway-authentication-controls - page: "Configure Corporate CA Trust" path: _build/agent-variants/security/configure-corporate-ca-trust.hermes.generated.mdx slug: configure-corporate-ca-trust diff --git a/docs/inference/set-up-ollama.mdx b/docs/inference/set-up-ollama.mdx index 24d34572e81..5952dad3dfd 100644 --- a/docs/inference/set-up-ollama.mdx +++ b/docs/inference/set-up-ollama.mdx @@ -210,7 +210,7 @@ The following settings control non-interactive selection: |---|---| | `NEMOCLAW_PROVIDER` | Set to `ollama`. | | `NEMOCLAW_MODEL` | Optional Ollama model tag. | -| `NEMOCLAW_PROVIDER_MODEL` | Compatibility fallback for the external NVIDIA QA non-interactive Ollama invocation recorded in [#6869](https://github.com/NVIDIA/NemoClaw/issues/6869), the only identified consumer. Its configuration is not stored in this repository, so changes here cannot migrate or verify the invocation. `NEMOCLAW_MODEL` takes precedence, and non-interactive re-onboarding ignores this fallback when the requested provider differs from the recorded provider. Remove the fallback after the QA owner confirms that the invocation uses `NEMOCLAW_MODEL` or is retired. | +| `NEMOCLAW_PROVIDER_MODEL` | Compatibility fallback for an external NVIDIA QA non-interactive Ollama invocation. `NEMOCLAW_MODEL` takes precedence. Non-interactive re-onboarding ignores this fallback when the requested provider differs from the recorded provider. | | `NEMOCLAW_YES` | Optional model download authorization when set to `1`. | Under `--non-interactive`, include `--yes` or set `NEMOCLAW_YES=1` to authorize a model download. diff --git a/docs/reference/enterprise-readiness.mdx b/docs/reference/enterprise-readiness.mdx index bdb823e274d..82b2cb65cb6 100644 --- a/docs/reference/enterprise-readiness.mdx +++ b/docs/reference/enterprise-readiness.mdx @@ -72,7 +72,7 @@ Each row links to deeper documentation and, when a concrete fix is in progress, | Monitoring and health | Supported | Use `$$nemoclaw status`, `$$nemoclaw logs --follow`, and `openshell term`. Refer to [CLI Commands Reference](commands). | | External telemetry and observability export | Supported with caveats | OpenClaw can emit conversation traces through its diagnostics plugin, and LangChain Deep Agents Code can explicitly opt into bounded-content OTLP/HTTP traces with `--observability`. Both paths require an operator-run host collector. NemoClaw does not manage the collector, remote exporter credentials, fleet-wide routing, metrics or logs export, or authenticated tenant identity. Treat exported prompts, responses, tool inputs, and tool results as sensitive application data. Refer to [Deep Agents Code OTLP Traces](commands#deep-agents-code-otlp-traces). Broader observability adapter work remains tracked in [#3915](https://github.com/NVIDIA/NemoClaw/issues/3915). | | Audit and session records | Supported with caveats | OpenClaw stores per-session JSONL event logs, and Hermes stores its own runtime state. Deep Agents Code has no equivalent session-log export, but it can emit bounded-content traces when you explicitly enable observability. Export is manual per sandbox. | -| Resource quotas | Supported with caveats | The entrypoint applies best-effort process and file-descriptor limits (`ulimit -u 512`, `ulimit -n 65536`). Set hard limits through the container runtime for fail-closed enforcement. Refer to [Process Controls](../security/best-practices#process-controls). | +| Resource quotas | Supported with caveats | The entrypoint applies best-effort process and file-descriptor limits (`ulimit -u 512`, `ulimit -n 65536`). Set hard limits through the container runtime for fail-closed enforcement. Refer to [Process Controls](../security/security-controls/process-controls). | | Cost and spend controls | Platform or partner-owned | Deny-by-default egress and routed inference reduce exfiltration and stray endpoints, but NemoClaw does not enforce per-token spend budgets. Set spend limits with your inference provider and monitor unattended agents. | | Credential isolation | Supported | Inference credentials stay on the host and never enter the sandbox; the agent reaches models through `inference.local`. CLI output redaction adds defense in depth, and OpenClaw sandboxes also run a memory secret scanner. Refer to [Credential Storage](../security/credential-storage) and [Security Best Practices](../security/best-practices). | | Upgrades and lifecycle | Supported with caveats | Upgrade NemoClaw, then run `$$nemoclaw rebuild` to recreate the sandbox with the current image while backing up and restoring state. Do not update the agent runtime in place inside the sandbox because the agent is image-pinned. Known gaps include config restore after rebuild ([#5202](https://github.com/NVIDIA/NemoClaw/issues/5202)) and version attachment flexibility ([#2217](https://github.com/NVIDIA/NemoClaw/issues/2217)). | @@ -113,8 +113,8 @@ Each one includes the current workaround or next step. | Controls bypassed outside the managed gateway path | Network policy and inference auth are not enforced if a runtime starts outside the NemoClaw-managed entrypoint. | Use NemoClaw-managed onboarding and sandbox entrypoints for production workflows. Refer to [Known Limitations](../security/best-practices#known-limitations). | | One consumer per messaging bot token | Two sandboxes sharing a bot token disconnect each other and drop messages. | Use a distinct bot token per sandbox. Refer to the messaging troubleshooting in [Troubleshooting](troubleshooting#messaging-bridge-appears-running-but-no-messages-arrive). | | In-sandbox config edits do not persist | Direct edits to agent config inside the running sandbox do not survive rebuilds. | Make durable config changes from the host by re-running `$$nemoclaw onboard`, not inside the sandbox. Refer to [Troubleshooting](troubleshooting). | -| Landlock filesystem enforcement degrades on old kernels | Filesystem restrictions fall back to container mounts below Linux kernel 5.13. | Run on kernel 5.13 or later for full enforcement. Refer to [Landlock LSM Enforcement](../security/best-practices#landlock-lsm-enforcement). | -| Best-effort capability and resource limits | Capability drops and ulimits skip silently when the runtime blocks them. | Pass `--cap-drop=ALL` and `--ulimit` at the container runtime, or set `NEMOCLAW_REQUIRE_CAP_DROP=1` to fail closed. Refer to [Process Controls](../security/best-practices#process-controls). | +| Landlock filesystem enforcement degrades on old kernels | Filesystem restrictions fall back to container mounts below Linux kernel 5.13. | Run on kernel 5.13 or later for full enforcement. Refer to [Landlock LSM Enforcement](../security/security-controls/filesystem-controls#landlock-lsm-enforcement). | +| Best-effort capability and resource limits | Capability drops and ulimits skip silently when the runtime blocks them. | Pass `--cap-drop=ALL` and `--ulimit` at the container runtime, or set `NEMOCLAW_REQUIRE_CAP_DROP=1` to fail closed. Refer to [Process Controls](../security/security-controls/process-controls). | ## Field Conversation Guidance diff --git a/docs/security/best-practices.mdx b/docs/security/best-practices.mdx index fa8b731d0d6..09bccf7cd84 100644 --- a/docs/security/best-practices.mdx +++ b/docs/security/best-practices.mdx @@ -1,17 +1,17 @@ --- # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -title: "NemoClaw Security Controls, Risks, and Posture Profiles" +title: "NemoClaw Security Posture and Control Trade-Offs" sidebar-title: "Security Best Practices" -description: "A risk framework for every configurable security control in NemoClaw: defaults, what you can change, and what happens if you do." -description-agent: "Presents a risk framework for every configurable security control in NemoClaw. Use when evaluating security posture, reviewing sandbox security defaults, or assessing control trade-offs." +description: "Compare NemoClaw security layers and posture profiles, then find the detailed control guidance for each trust boundary." +description-agent: "Explains NemoClaw security layers, posture profiles, and control trade-offs. Use when choosing a security posture or finding the detailed owner for a sandbox security control." keywords: ["nemoclaw security best practices", "sandbox security controls risk framework"] content: type: "concept" --- NemoClaw ships with deny-by-default security controls across five layers: network, filesystem, process, gateway authentication, and inference. -You can tune every control, but each change shifts the risk profile. -This page documents each configurable control, its default, what it protects, the concrete risk of relaxing it, and a recommendation for common use cases. +This page compares those layers, explains the controls that operators change at runtime, and helps you choose a posture profile. +The **Security Controls** navigation group owns the detailed filesystem, process, and gateway authentication guidance. For background on how the layers fit together, refer to [How It Works](../about/how-it-works). @@ -282,571 +282,15 @@ Broader binary access would let unrelated sandbox processes send data to Tavily ## Filesystem Controls -NemoClaw restricts which paths the agent can read and write, protecting system binaries, configuration files, and gateway credentials. - -OpenShell covers additional filesystem enforcement details, including `hard_requirement` compatibility mode for Landlock and policy path validation rules. -Refer to the [Filesystem Controls](https://docs.nvidia.com/openshell/latest/security/best-practices.html#filesystem-controls) section of the OpenShell Security Best Practices. - -### Read-Only System Paths - -The container mounts system directories read-only to prevent the agent from modifying binaries, libraries, or configuration files. - -| Aspect | Detail | -|---|---| -| Default | `/usr`, `/lib`, `/proc`, `/dev/urandom`, `/app`, `/etc`, `/var/log`, and `/var/lib/dpkg` are read-only. | -| What you can change | Add or remove paths in the `filesystem_policy.read_only` section of the policy file. | -| Risk if relaxed | Making `/usr` or `/lib` writable lets the agent replace system binaries (such as `curl` or `node`) with trojanized versions. Making `/etc` writable lets the agent modify DNS resolution, TLS trust stores, or user accounts. | -| Recommendation | Never make system paths writable. If the agent needs a writable location for generated files, use a subdirectory of `/sandbox`. | - -### Agent Config Directory - - - -The `/sandbox/.openclaw` directory contains the OpenClaw gateway configuration (model routing, CORS settings, channel config). -The current entrypoint reads the gateway auth token from OpenClaw config when present, exports it as `OPENCLAW_GATEWAY_TOKEN`, and writes it to `/tmp/nemoclaw-proxy-env.sh` so interactive sandbox sessions can reach the gateway through system-wide shell hooks. -In root mode, the gateway process still runs as the separate `gateway` user, but the token is intentionally available to sandbox shells for local gateway access. - -Writable agent state such as plugins, skills, hooks, and workspace metadata lives directly under `/sandbox/.openclaw`. - -By default, this directory starts writable so the agent can manage its own config, install skills, and write to standard home-directory paths natively. -For sensitive workloads, use a reviewed host-side immutability workflow after initial setup so the sandbox user cannot change config or high-risk state entry points. -The immutability workflow derives its path plan from the selected agent manifest. -For OpenClaw, it locks `agents`, `canvas`, `cron`, `devices`, `extensions`, `hooks`, `memory`, `plugins`, `profiles`, `skills`, `telegram`, `wechat`, `whatsapp`, `workspace`, and `workspace-*` directories to `root:sandbox` and removes group and world write access. -The root-only helper traverses from opened directory descriptors with no-follow semantics instead of using recursive pathname `chown` or `chmod`. -Read-only preflight and unlock operations reject unsafe external symlinks, hardlinks, special files, cross-device entries, and entries that race the traversal without modifying them. -After the top-level config binding is frozen, lockdown makes containment monotonic. -It removes unsafe symlinks, special entries, and protected-root names that are not directories through descriptor-relative operations without following their targets. -For protected regular files, lockdown publishes a fresh inode, severing hardlinks while preserving file content, read/execute mode, timestamps, and supported extended attributes; this also revokes write authority held through a descriptor opened before `shields up`. -The OpenClaw gateway (a member of the `sandbox` group) keeps read access to plugin and agent code; the sandbox user can no longer write them. -The same workflow locks the secret-bearing `credentials` and `identity` directories. -The guard sets each confidentiality root to `root:sandbox 0710`, including a non-empty `credentials` directory. -It sets every nested directory and file to `root:root` and removes all group and world permission bits. -The sandbox group cannot list, create, or remove entries in a confidentiality root, and neither the sandbox user nor gateway can read stored secrets. -They can inspect metadata for a direct child only when they already know its name. -Probing a missing direct child, such as the legacy `credentials/oauth.json`, returns `ENOENT` instead of `EACCES`. -Restoring the mutable-default posture returns those directories to `sandbox:sandbox 2770`. -For plan-aware current images and host-injected transitions, each agent manifest declares only its own protected paths, confidential paths, dynamic prefixes, and writable subpaths. -The lock helper applies only that selected manifest plan and skips declared paths that are not present. -Historical OpenClaw and Hermes images that have a bundled helper but no generated plan use the helper's reviewed legacy inventory until the sandbox is rebuilt. -State directories without a Shields declaration remain mutable. -Inside a locked tree, the helper keeps each `agents//sessions/` root at `sandbox:sandbox 2770` so the OpenClaw TUI can create and write session metadata under an otherwise root-owned parent. -After containment, when an agent directory has no `sessions` entry, lockdown creates that carve-out root. -An agent booting for the first time under an active lock can then write sessions. -It validates the carve-out root but deliberately does not traverse or rewrite live session descendants. -Cross-device entries, detected traversal races, or failures to remove or replace an unsafe entry make lockdown fail closed with the exact path and reason. - -- **DAC permissions (default).** - The sandbox user owns `/sandbox/.openclaw` with mode `2770` (setgid `sandbox:sandbox`) and `openclaw.json` with mode `660`, so the agent and its group can read and write config directly. - A reviewed host-side immutability workflow should compare the intended ownership and mode with the live sandbox filesystem before treating the config tree as locked. -- **Config integrity hash.** - The image includes a SHA256 hash of `openclaw.json`. - In the default mutable state, `.config-hash` is sandbox-owned and is not a tamper-proof trust anchor, so startup does not fail closed on that hash. - When the hash is root-owned and read-only, startup enforces it and refuses to start if the hash does not match. -- **Content integrity seal.** - A clean immutable config lock can capture a SHA-256 seal of `openclaw.json` and other locked files into host-side state. - Verification recomputes hashes inside the sandbox and surfaces drift on mismatch, so a host-root tamper that flips permissions back to `444 root:root` after rewriting the file is still flagged. - Sandboxes locked before the seal landed have no recorded hash; permission-only verification cannot prove their bytes match the image original, so the seal is **not** a retroactive proof of integrity for legacy state. - The same limitation applies when the locked file set grew after the existing seal was captured. - Rebuild the sandbox for a known-good baseline before trusting a new seal. -- **Gateway token environment.** - The gateway exports `OPENCLAW_GATEWAY_TOKEN` and writes it to `/tmp/nemoclaw-proxy-env.sh` for interactive sandbox sessions. - Keep this in mind when deciding whether a workload should run with mutable config or an immutable config posture. - -| Aspect | Detail | -|---|---| -| Default | The sandbox keeps `/sandbox/.openclaw` writable (`2770 sandbox:sandbox`), sets `openclaw.json` to `660 sandbox:sandbox`, lets the agent manage state directly, and has the gateway place `OPENCLAW_GATEWAY_TOKEN` in `/tmp/nemoclaw-proxy-env.sh` for interactive shells. | -| What you can change | Apply a reviewed host-side immutability workflow to lock config and state directories with DAC permissions and the immutable flag where available. | -| Risk of default | A writable `.openclaw` directory lets the agent modify its own gateway config: disabling CORS or redirecting inference to an attacker-controlled endpoint. | -| Recommendation | For always-on assistants handling sensitive workloads, lock config after initial setup. For development workflows, the writable default is appropriate. | - - - - -The `/sandbox/.hermes` directory contains Hermes runtime configuration, generated environment settings, logs, platform state, and durable database state. -NemoClaw writes `config.yaml` and `.env` during onboarding and rebuilds. -Direct edits to these files can be overwritten when NemoClaw regenerates the image. - -Hermes also stores runtime state such as `state.db`, logs, and platform sessions under the `.hermes` tree. -Messaging sessions such as WhatsApp pairing can remain mutable by design so they survive rebuilds. -For plan-aware current images, the Shields workflow derives the Hermes lock plan from its agent manifest. -Historical Hermes images that have a bundled helper but no generated plan use the helper's reviewed legacy inventory until the sandbox is rebuilt. -It locks `cron`, `hooks`, `platforms`, `plugins`, `profiles`, `skills`, `skins`, `weixin`, and `workspace` to `root:sandbox`. -The `profiles/dashboard-home` carve-out remains `sandbox:sandbox 0700`, and the guard does not traverse or rewrite its descendants. -It locks the `pairing` confidentiality root to `root:sandbox 0710`. -Hermes runtime directories without a Shields declaration remain mutable. - -The shared state-directory guard applies the manifest declaration to `pairing` on current Hermes images. -On historical images, the reviewed legacy inventory also treats present `credentials` and `identity` directories as confidentiality roots. -The guard sets the root to `root:sandbox 710`, keeps it traversable but unlistable to the sandbox group, and sets every descendant to `root:root` with no group or world permission bits. -As a result, a known-name probe for a missing direct child returns `ENOENT`, while directory listing, nested traversal, and protected-file reads return `EACCES`. - -| Aspect | Detail | -|---|---| -| Default | The Hermes config tree contains NemoClaw-generated config plus mutable runtime state. | -| What you can change | Use host-side NemoClaw commands for durable model, provider, messaging, and policy changes; inspect files directly only for debugging. | -| Risk of direct edits | Direct edits to generated config can drift from the host registry and may be lost on rebuild. | -| Recommendation | For sensitive workloads, keep generated config under NemoClaw control and back up Hermes state before destructive operations. | - - - - -The `/sandbox/.deepagents` directory contains Deep Agents Code runtime state and NemoClaw-generated configuration. -NemoClaw writes `config.toml` during onboarding and rebuilds. -Direct edits to this file can be overwritten when NemoClaw regenerates the managed inference route. - -The managed Deep Agents image deliberately omits raw provider and service credentials from generated configuration. -Credential-bearing files such as `.deepagents/.env` and user-authored `.deepagents/.mcp.json` are treated as user-managed files and are not included in NemoClaw snapshots. -The managed `.deepagents/.nemoclaw-mcp.json` projection contains OpenShell placeholders and is reconstructed from host-side registry state. -The Shields workflow derives the Deep Agents lock plan from its agent manifest. -The `agent/skills` declaration locks the top-level `agent` directory, and the `skills` declaration locks the top-level `skills` directory. -The `.state` directory remains mutable. - -| Aspect | Detail | -|---|---| -| Default | The Deep Agents config tree contains NemoClaw-generated `config.toml`, managed MCP projection state, and mutable Deep Agents memory and skill state. | -| What you can change | Use host-side NemoClaw commands for durable model, provider, managed MCP, and policy changes; inspect or edit memory and skills through `dcode` or direct file access when appropriate. | -| Risk of direct edits | Direct edits to generated config can drift from the host registry and may be lost on rebuild. Storing credentials in `.deepagents/.env` or user `.mcp.json` moves them outside the managed credential boundary. | -| Recommendation | Keep generated config under NemoClaw control. Use OpenShell providers and NemoClaw MCP commands for credentials, and back up Deep Agents state before destructive operations. | - - - -### Writable Paths - -The agent has read-write access to `/sandbox`, `/tmp`, `/dev/null`, and `/dev/pts`. - -| Aspect | Detail | -|---|---| -| Default | `/sandbox` (agent workspace), `/tmp` (temporary files), `/dev/null`, and `/dev/pts` (the devpts pseudo-terminal directory, required so PTY-based tools such as `tmux`, `script`, and interactive shells can allocate a terminal). | -| What you can change | Add additional writable paths in `filesystem_policy.read_write`. | -| Risk if relaxed | Each additional writable path expands the agent's ability to persist data and potentially modify system behavior. Adding `/var` lets the agent write to log directories. Adding `/home` gives access to other user directories. | -| Recommendation | Keep writable paths to `/sandbox` and `/tmp`. If the agent needs a persistent working directory, create a subdirectory under `/sandbox`. | - -### Landlock LSM Enforcement - -Landlock is a Linux Security Module that enforces filesystem access rules at the kernel level. - - - -| Aspect | Detail | -|---|---| -| Default | `compatibility: best_effort`. The entrypoint applies Landlock rules when the kernel supports them and silently skips them on older kernels. | -| What you can change | This is a NemoClaw default, not a user-facing knob. | -| Risk if relaxed | On kernels without Landlock support (pre-5.13), filesystem restrictions rely solely on container mount configuration, which is less granular. | -| Recommendation | Run on a kernel that supports Landlock (5.13+). Ubuntu 22.04 LTS and later include Landlock support. | - - - - -| Aspect | Detail | -|---|---| -| Default | `compatibility: best_effort`. The entrypoint applies Landlock rules when the kernel supports them and silently skips them on older kernels. | -| What you can change | This is a NemoClaw default, not a user-facing knob. | -| Risk if relaxed | On kernels without Landlock support (pre-5.13), filesystem restrictions rely solely on container mount configuration, which is less granular. | -| Recommendation | Run on a kernel that supports Landlock (5.13+). Ubuntu 22.04 LTS and later include Landlock support. | - - - - -| Aspect | Detail | -|---|---| -| Default | `compatibility: strict`. Deep Agents sandbox startup fails closed when OpenShell cannot enforce the managed filesystem policy. | -| What you can change | This is a NemoClaw Deep Agents invariant, not a user-facing knob. | -| Risk if relaxed | Silent Landlock degradation would leave the terminal coding harness with weaker filesystem isolation while still reporting a successful sandbox. | -| Recommendation | Run Deep Agents on a kernel and runtime that support Landlock enforcement. Rebuild or move hosts if startup reports an enforcement failure. | - - +Review filesystem defaults, writable paths, agent state, and Landlock enforcement in [Understand Filesystem Controls](./security-controls/filesystem-controls). ## Process Controls -NemoClaw limits the capabilities, user privileges, and resource quotas available to processes inside the sandbox. - -OpenShell enforces additional process-level controls not covered here, including seccomp BPF socket domain filters and a specific enforcement application order (namespace entry, privilege drop, Landlock, seccomp). -Refer to the [Process Controls](https://docs.nvidia.com/openshell/latest/security/best-practices.html#process-controls) section of the OpenShell Security Best Practices. - -### 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. -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`. -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. -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. -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)). - - -For additional protection, pass `--cap-drop=ALL` with `docker run` or Compose. -Refer to [Review Sandbox Hardening](../manage-sandboxes/configure-sandboxes/review-sandbox-hardening). - - -| 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. | -| 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. | - -### Gateway Process Isolation - -Gateway and agent UID isolation depends on the container process topology. -A direct root-entrypoint container runs the gateway as the separate `gateway` user and the agent as the `sandbox` user. -An OpenShell-managed container has OpenShell as PID 1 and launches nonroot `nemoclaw-start`, so the supervisor, gateway, and agent all use the `sandbox` UID. - -| Aspect | Detail | -|---|---| -| Default | Direct root entrypoints use `setpriv` for gateway UID isolation. The OpenShell-managed topology runs the gateway and agent under the same sandbox UID because `no-new-privileges` prevents the nonroot entrypoint from changing users. | -| What you can change | This is not a user-facing knob. The selected container topology determines whether the entrypoint can step down from root to the gateway UID. | -| Risk if relaxed | A same-UID agent can signal peer processes and can attempt to imitate the expected gateway process shape. The root managed controller prevents PID-reuse mistakes, but it cannot prove provenance against a malicious same-UID process or provide the direct root-entrypoint restart seal for mutable config. | -| Recommendation | Use a direct root-entrypoint deployment when separate gateway and agent UIDs are required. Treat the managed controller as authenticated lifecycle and exact-target safety, not as a same-UID provenance boundary. | - -### No New Privileges - -The `no-new-privileges` flag prevents processes from gaining additional privileges through setuid binaries or capability inheritance. - -| Aspect | Detail | -|---|---| -| Default | OpenShell sets `PR_SET_NO_NEW_PRIVS` using `prctl()` inside the sandbox process as part of the seccomp filter setup. The NemoClaw Compose example also shows the equivalent `security_opt: no-new-privileges:true` setting. | -| What you can change | OpenShell's seccomp path enforces this inside the sandbox. It is not a user-facing knob. | -| Risk if relaxed | Without this flag, a compromised process could execute a setuid binary to escalate to root inside the container, then attempt container escape techniques. | -| Recommendation | No action needed. OpenShell enforces this automatically when the sandbox network policy is active. In the OpenShell-managed topology, this flag also means the nonroot entrypoint and gateway remain under the sandbox UID. | - -### Process Limit - -A process limit caps the number of processes the sandbox user can spawn. -The entrypoint sets both soft and hard limits using `ulimit -u 512`. -This behavior is best effort. -If the container runtime restricts `ulimit` modification, the entrypoint logs a security warning and continues without the limit. - -| Aspect | Detail | -|---|---| -| Default | 512 processes (`ulimit -u 512`), best-effort. | -| What you can change | Increase or decrease the limit with `--ulimit nproc=N:N` in `docker run` or the `ulimits` section in Compose. The runtime-level ulimit takes precedence over the entrypoint's setting. | -| Risk if relaxed | Removing or raising the limit makes the sandbox vulnerable to fork-bomb attacks, where a runaway process spawns children until the host runs out of resources. If the entrypoint cannot set the limit (logs `[SECURITY] Could not set soft/hard nproc limit`), the container runs without process limits. | -| Recommendation | Keep the default at 512. If the agent runs workloads that spawn many child processes (such as parallel test runners), increase to 1024 and monitor host resource usage. If the entrypoint logs a warning about ulimit restrictions, set the limit through the container runtime instead. | - -### Open File Descriptor Limit - -An open file descriptor limit caps the number of files, sockets, and pipes the sandbox user can hold open at once. -The entrypoint sets both soft and hard limits using `ulimit -n 65536`. -This behavior is best effort. -If the container runtime restricts `ulimit` modification, the entrypoint logs a security warning and continues without the limit. - -| Aspect | Detail | -|---|---| -| Default | 65536 open files, soft and hard (`ulimit -n 65536`), best-effort. | -| What you can change | Increase or decrease the limit with `--ulimit nofile=N:N` in `docker run` or the `ulimits` section in Compose. The runtime-level ulimit takes precedence over the entrypoint's setting. | -| Risk if relaxed | Without this cap, the sandbox inherits the Docker daemon default (`nofile` ~1048576). A runaway or hostile process can then open file descriptors until it exhausts them, causing a denial of service that can starve the gateway, the agent, or the host of file handles. If the entrypoint cannot set the limit (logs `[SECURITY] Could not set soft/hard nofile limit`), the container runs without a file-descriptor cap. Ref [#4527](https://github.com/NVIDIA/NemoClaw/issues/4527). | -| Recommendation | Keep the default at 65536. If the agent legitimately keeps many connections or files open, raise it deliberately and monitor host file-descriptor usage. If the entrypoint logs a warning about ulimit restrictions, set the limit through the container runtime instead. | - - - -### Deep Agents Resource Limit Enforcement - -Managed Deep Agents uses stricter enforcement than the best-effort entrypoint behavior described above. -The managed Deep Agents image applies the 512-process and 65,536-file-descriptor caps to the long-running sandbox entrypoint tree and to direct managed `dcode` launches. -During Docker-driver onboarding, NemoClaw also configures the container with exact `nproc=512:512` and `nofile=65536:65536` limits so the managed entrypoint and fresh exec or connect processes start under the same hard caps. -The container-level limits and managed startup command remain in effect when you stop and start the sandbox or restart the OpenShell gateway. -It also applies and verifies the caps in Bash login and interactive shells because fresh `openshell sandbox exec` and connect shells do not inherit the dcode entrypoint child's lowered limits. -For managed Deep Agents, successful verification requires both the soft and hard limits to equal 512 processes and 65,536 file descriptors; a lower inherited file-descriptor default such as 1,024 is not accepted as successful hardening. - -If the image-baked resource-limit helper is missing or the effective limits do not match policy after hardening, the Deep Agents entrypoint and direct managed launcher refuse to start. -The entrypoint and launcher complete this verification before proxy setup or user-supplied commands run. -A login or interactive shell remains available when the helper is missing or its limits cannot be verified, but it prints `[SECURITY] Sandbox resource limits were NOT hardened for this shell.` -OpenShell creates those fresh exec and connect processes outside the entrypoint tree, so an image layer cannot make them inherit the entrypoint child's lowered limits. -The shell compatibility exception can be removed when OpenShell guarantees that every exec and connect process starts under enforced caps or exposes a fail-closed resource-limit contract. -For custom container launches outside NemoClaw's managed Docker-driver onboarding path, set hard `nproc` and `nofile` limits at the container runtime when you require fail-closed enforcement. - -### Deep Agents Thread Auto-Approval Capability - -Managed Deep Agents sandboxes separate the host-configured capability from the active approval state of each TUI thread. -The default `disabled` mode keeps the TUI auto-approval choice and `dcode -y` unavailable. -An operator can select `thread-opt-in` through a named transactional rebuild, but each thread still requires an explicit TUI choice or `dcode -y` invocation before tool calls run without further confirmation. - -NemoClaw stores the configured mode in a root-owned, mode `0444` image file rather than trusting runtime environment variables. -A missing, malformed, symlinked, writable, unreadable, or incorrectly owned capability file resolves to `disabled`. -Ambient `NEMOCLAW_DCODE_AUTO_APPROVAL*` values cannot enable the capability. - -When a thread activates auto-approval, the TUI shows the upstream active-state indicator and prints a warning. -NemoClaw clears that active state for a new process, `/clear`, `/force-clear`, a thread switch or resume, and an agent switch. -The host-side `status` command reports only the configured capability because it does not attest to the current state of a specific TUI thread. - -| Aspect | Detail | -|---|---| -| Default | `disabled`. Interactive tool calls keep their approval prompts, and thread auto-approval cannot be selected. | -| What you can change | Use `--dcode-auto-approval thread-opt-in` during a named managed Deep Agents rebuild. Use `--dcode-auto-approval disabled` in another rebuild to revoke the capability. | -| Risk if enabled | A prompt injection, untrusted repository, or mistaken plan can cause tool calls, including shell commands, to run without another human confirmation for the rest of the active thread. | -| Remaining controls | OpenShell egress policy, credential isolation and rewriting, the managed inference route, managed MCP validation, filesystem and process controls, and the other managed runtime restrictions remain active. | -| Recommendation | Keep `disabled` for sensitive or unfamiliar work. Enable `thread-opt-in` only for bounded tasks in a reviewed workspace, watch the active-state indicator, and start a new thread or rebuild with `disabled` when unattended tool execution is no longer acceptable. | - - -Treat `thread-opt-in` as permission for unattended shell execution inside the sandbox, not as a policy bypass. -The sandbox boundary limits where commands run and what external resources they can reach, but it does not make an automatically approved command harmless to writable workspace data. - - -### Headless Deep Agents Approval Boundary - -Interactive `dcode` sessions keep destructive tools behind the Deep Agents Code approval UI. -Headless `dcode -n` is an explicit automation boundary with no approval UI. -The managed headless path automatically approves non-shell tool requests such as file writes and edits, while still disabling shell execution, startup commands, interpreter tool calling, executable hooks, unmanaged MCP files, nested remote sandboxes, remote async subagents, and alternate model routes. - -| Aspect | Detail | -|---|---| -| Default | Interactive `dcode` prompts for destructive tools. Headless `dcode -n` auto-approves non-shell tools and keeps shell execution disabled. | -| What you can change | Choose interactive `dcode` when you need to review tool calls. Use `dcode -n` only for tasks where unattended file edits are acceptable. The interactive `thread-opt-in` capability does not change this headless boundary. | -| Risk if relaxed | Treating headless mode like an interactive approval session can let file edits happen without a human prompt. | -| Recommendation | Use the interactive TUI for sensitive repositories or destructive tasks. Reserve `dcode -n` for bounded automation with a reviewed workspace and policy. | - - - -### Non-Root User - -The sandbox runs agent processes as a dedicated `sandbox` user and group. -The entrypoint starts as root for privilege separation, then drops to the `sandbox` user for all agent commands. - -| Aspect | Detail | -|---|---| -| Default | `run_as_user: sandbox`, `run_as_group: sandbox`. A separate `gateway` user runs the gateway process. | -| What you can change | Change the `process` section in the policy file to run as a different user. | -| Risk if relaxed | Running as `root` inside the container gives the agent access to modify any file in the container filesystem and increases the impact of container escape vulnerabilities. | -| Recommendation | Never run as root. Keep the `sandbox` user. | - -### PATH Hardening - -The entrypoint locks the `PATH` environment variable to system directories, preventing the agent from injecting malicious binaries into command resolution. - -| Aspect | Detail | -|---|---| -| Default | The default sandbox entrypoint sets `PATH` to `/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin` at startup. Agent-specific images may add locked read-only runtime directories, such as `/opt/venv/bin` for LangChain Deep Agents Code. | -| What you can change | This is not a user-facing knob. The entrypoint enforces it. | -| Risk if relaxed | Without PATH hardening, the agent could create an executable named `curl` or `git` in a writable directory earlier in the PATH, intercepting commands run by the entrypoint or other processes. | -| Recommendation | No action needed. The entrypoint handles this automatically. | - -### Build Toolchain Removal - -The Dockerfile removes compilers and network probes from the runtime image. - -| Aspect | Detail | -|---|---| -| Default | The Dockerfile purges `gcc`, `gcc-12`, `g++`, `g++-12`, `cpp`, `cpp-12`, `make`, `netcat-openbsd`, `netcat-traditional`, and `ncat` from the sandbox image. | -| What you can change | Modify the Dockerfile to keep these tools, or install them at runtime if package manager access is allowed. | -| Risk if relaxed | A compiler lets the agent build arbitrary native code, including kernel exploits or custom network tools. `netcat` enables arbitrary TCP connections that bypass HTTP-level policy enforcement. | -| Recommendation | Keep build tools removed. If the agent needs to compile code, run the build in a separate, purpose-built container and copy artifacts into the sandbox. | - -### Image Digest Pinning - -The blueprint references the sandbox image by an immutable `@sha256:` digest instead of a mutable tag such as `:latest`. -A registry compromise or accidental force-push cannot silently swap the sandbox image. - -| Aspect | Detail | -|---|---| -| Default | `nemoclaw-blueprint/blueprint.yaml` pins the sandbox image by digest. A CI regression test blocks any mutable-tag reference from merging. | -| What you can change | Contributors bumping the sandbox image must update the digest in `blueprint.yaml`. Release tooling should rewrite the digest automatically. | -| Risk if relaxed | Reverting to a mutable tag (`:latest`) allows a registry-side change to replace the sandbox image without any blueprint update, which is a supply-chain risk. | -| Recommendation | Always reference the sandbox image by digest. If you build a custom image with the onboarding `--from` path, the digest constraint does not apply to your local build. | - - - -### Auth Profile Permissions - -The entrypoint and migration flows enforce `chmod 600` on all `auth-profiles.json` files under `~/.openclaw`. -This prevents other users on the host from reading stored credentials. - -| Aspect | Detail | -|---|---| -| Default | `600` permissions applied recursively at startup and after migration restores. | -| What you can change | This is not a user-facing knob. The entrypoint enforces it. | -| Risk if relaxed | Looser permissions let other users or processes on the host read provider API keys and tokens stored in auth profiles. | -| Recommendation | No action needed. If you see a `permission denied` error when reading auth profiles, verify that you are running as the same user who created them. | - - +Review capability drops, resource limits, runtime identity, and image hardening in [Understand Process Controls](./security-controls/process-controls). ## Gateway Authentication Controls - - -The OpenClaw gateway authenticates devices that connect to the Control UI dashboard. -NemoClaw hardens these defaults at image build time. - -### Device Authentication - -Device authentication requires each connecting device to go through a pairing flow before it can interact with the gateway. - -| Aspect | Detail | -|---|---| -| Default | The base Dockerfile enables device authentication for loopback dashboards. Standard onboarding currently applies a managed compatibility opt-out for immediate dashboard access. NemoClaw also disables device authentication for non-loopback `CHAT_UI_URL` values. | -| What you can change | Outside managed onboarding, set `NEMOCLAW_DISABLE_DEVICE_AUTH=1` only as a deliberate build-time opt-out. The setting and its managed-vs-operator provenance are baked into `openclaw.json` audit metadata and the config is verified by hash at startup. | -| Risk if relaxed | Disabling device auth allows any device on the network to connect to the gateway without proving identity. This is dangerous when combined with LAN-bind changes or cloudflared tunnels in remote deployments, resulting in an unauthenticated, publicly reachable dashboard. | -| Recommendation | Prefer loopback access or SSH port forwarding so device authentication stays enabled. If a browser-only remote dashboard requires the compatibility setting, use HTTPS and restrict who can reach the dashboard. | - -### Gateway Bind Address - -NemoClaw binds the OpenShell gateway to loopback by default. - -| Aspect | Detail | -|---|---| -| Default | `NEMOCLAW_GATEWAY_BIND_ADDRESS=127.0.0.1`. | -| What you can change | Keep Docker-driver gateways on loopback. Set `NEMOCLAW_DASHBOARD_BIND=0.0.0.0` during onboarding and on later `connect` calls for remote dashboard/API access. Recreate a local-only sandbox before changing it to a remote bind. | -| Risk if relaxed | Other hosts on the network may be able to reach the OpenShell gateway. NemoClaw rejects wildcard Docker-driver gateway binds while gateway JWT auth is active. | -| Recommendation | Keep the gateway loopback default and expose only the dashboard forward when remote access is needed. | - -### Gateway Compatibility Container - -On Linux hosts whose glibc is older than the OpenShell gateway binary requires, NemoClaw can run `openshell-gateway` in a Docker compatibility container so the Docker-driver gateway still starts. This path requires the explicit opt-in `NEMOCLAW_OPENSHELL_GATEWAY_CONTAINER_PATCH=1`. - -| Aspect | Detail | -|---|---| -| Default | NemoClaw does not auto-enable the compatibility container on ABI mismatch. If `NEMOCLAW_OPENSHELL_GATEWAY_CONTAINER_PATCH=1` is set, the container keeps the main gateway listener on `127.0.0.1`, uses host networking so OpenShell computes the same Docker bridge callback addresses as a host-side gateway, mounts the Docker socket read-only, drops Linux capabilities, sets `no-new-privileges`, and publishes no extra Docker ports. | -| What you can change | Opt in with `NEMOCLAW_OPENSHELL_GATEWAY_CONTAINER_PATCH=1`, keep the path disabled with `NEMOCLAW_OPENSHELL_GATEWAY_CONTAINER_PATCH=0`, or run on a host/OpenShell build combination where the gateway binary launches directly. | -| Risk if relaxed | The Docker socket remains a privileged host API even when bind-mounted read-only. Treat this mode as equivalent to trusting the host user that can drive Docker, and do not enable it on untrusted shared hosts. | -| Recommendation | Prefer a host with glibc 2.39 or newer, which OpenShell 0.0.99 supports directly, and use the compatibility container only as an explicit local bridge on an older trusted host. | - -See [OpenShell Gateway Compatibility Review](./openshell-0.0.72-compatibility-review) for the unchanged compatibility-container source-of-truth boundaries. - -### Insecure Auth Derivation - -The `allowInsecureAuth` setting controls whether the gateway permits non-HTTPS authentication. - -| Aspect | Detail | -|---|---| -| Default | Derived from the `CHAT_UI_URL` scheme at build time. When the URL uses `http://` (local development), insecure auth is allowed. When it uses `https://` (remote or production), insecure auth is blocked. | -| What you can change | This is derived automatically from `CHAT_UI_URL`. Set `CHAT_UI_URL` to an `https://` URL to enforce secure auth. | -| Risk if relaxed | Allowing insecure auth over HTTPS defeats the purpose of TLS, because authentication tokens transit in cleartext. | -| Recommendation | Use `https://` for any deployment accessible beyond `localhost`. The default local URL (`http://127.0.0.1:18789`) correctly allows insecure auth for local development. | - -OpenClaw's security audit keeps NemoClaw-managed loopback `allowInsecureAuth` findings and provenance-known loopback device-auth opt-out findings visible as accepted findings instead of counting them as unexplained active findings. -Device-auth findings record whether the opt-out came from NemoClaw's managed onboarding compatibility behavior or an operator-provided `NEMOCLAW_DISABLE_DEVICE_AUTH=1`; an opt-out with missing provenance remains active. -For audit reporting, NemoClaw treats a non-loopback `CHAT_UI_URL`, an onboard-time `NEMOCLAW_DASHBOARD_BIND=0.0.0.0`, or WSL's default all-interface dashboard forward as remote dashboard exposure. -For an explicit `NEMOCLAW_DASHBOARD_BIND=0.0.0.0` bind, use the same setting on later `connect` calls. -If the sandbox was created without that explicit setting, NemoClaw refuses the remote forward until you recreate it with `NEMOCLAW_DASHBOARD_BIND=0.0.0.0 $$nemoclaw onboard --recreate-sandbox`; this keeps the generated audit state aligned with the host exposure state. -On WSL, the ready summary still uses a loopback URL, but the generated audit configuration leaves the device-auth and insecure-auth findings active. -For an explicit remote bind with a loopback `CHAT_UI_URL`, NemoClaw disables device auth and enables OpenClaw's Host-header origin fallback because the browser's remote origin is not known at image-build time. Both settings expand access and must remain explicit; use HTTPS or an SSH local forward when possible. -In that state, NemoClaw does not add the loopback-only audit suppressions, so the resulting device-auth, insecure-auth, and Host-header fallback findings remain active. -The generated configuration uses exact audit check IDs and flag details, records why each setting is present, and leaves the original severity and remediation under `suppressedFindings` in JSON output. -The audit also reports that suppressions are active so you can review the accepted risk. -These suppressions change audit reporting only. -They do not make either flag safe, weaken enforcement, or suppress unrelated findings. - -Review the accepted findings and their recorded reasons: - -```bash -openclaw security audit --json | jq '.suppressedFindings' -``` - -Remove the underlying risky condition when dashboard compatibility no longer requires it. -Remove these suppressions only after the pinned OpenClaw audit contract test proves that OpenClaw natively classifies intentional loopback development HTTP without them, or after NemoClaw onboarding defaults `CHAT_UI_URL` to `https://localhost` with a generated local certificate. -Regression contracts: `test/generate-openclaw-config-security-audit.test.ts` locks generated suppression scope, `test/openclaw-security-audit-suppressions-real.test.ts` locks the pinned OpenClaw check IDs and details, and `test/e2e/live/dashboard-remote-bind.test.ts` proves a clean-host remote bind leaves all three risky findings active. The preceding removal condition applies to all three contracts. - -### Auto-Pair Client Allowlist - -The auto-pair watcher automatically approves device pairing requests from recognized clients, so you do not need to manually approve the Control UI. - -| Aspect | Detail | -|---|---| -| Default | Startup auto-pairing and `connect`-time approval share one policy. NemoClaw approves devices only when `clientId` is `cli`, `openclaw-cli`, or `openclaw-control-ui`, and only for `operator.pairing`, `operator.read`, and `operator.write` scopes. An allowlisted `clientMode` alone is never sufficient; all other clients or scopes are rejected and logged. | -| What you can change | This is not a user-facing knob. The allowlist is defined by NemoClaw's OpenClaw device-approval helper. | -| Risk if relaxed | Approving all device types without validation lets rogue or unexpected clients pair with the gateway unchallenged. | -| Recommendation | No action needed. NemoClaw handles this automatically at startup and during `connect` for late scope upgrades. If you see `[auto-pair] rejected unknown client=...` in the logs, investigate the source of the unexpected connection. | - -#### Approve administrative scopes manually - -NemoClaw automatically approves only the `operator.pairing`, `operator.read`, and `operator.write` scopes. -It never automatically approves `operator.admin`. -Operations that require that scope, such as creating a cron job, need your explicit approval. - -From the host, open the prepared connect shell: - -```bash -$$nemoclaw connect -``` - -In that shell, run the administrative command once to create the pending request, and note the exact `requestId` in the failure. -Then inspect the pending requests: - -```bash -openclaw devices list --json -``` - -Find that exact `requestId`, and verify that its client, device, and requested scopes match the operation you just attempted. -Approve that request by its `requestId`: - -```bash -openclaw devices approve -``` - -Retry the original administrative command after the approval succeeds. - - -Approve only the exact `requestId` emitted by your command and only the client, device, and scopes you expect. -Do not approve an unexpected client or an unrelated `operator.admin` request. - - - - - -Hermes exposes an OpenAI-compatible API on the forwarded Hermes port and can optionally expose the native Hermes dashboard. -Do not publish those endpoints on shared or public networks unless you put them behind your own access controls. -NemoClaw still keeps provider credentials in OpenShell and routes model traffic through `inference.local`. -Generated Hermes runtime files use OpenShell resolver placeholders for managed-tool and messaging credentials. -Hermes startup rejects raw secret-shaped values in sandbox-visible environment or config fields, while allowing empty values, migration sentinels, OpenShell resolver placeholders, and expected Slack placeholder forms. - - - -### CLI Secret Redaction - -The CLI automatically redacts secret patterns (API keys, bearer tokens, provider credentials) from command output and error messages before logging them. - -| Aspect | Detail | -|---|---| -| Default | Enabled. The runner redacts secrets from stdout, stderr, and thrown error messages. | -| What you can change | This is not a user-facing knob. The CLI enforces it on all command output paths. | -| Risk if relaxed | Without redaction, secrets could appear in terminal scrollback, log files, or debug output shared in bug reports. | -| Recommendation | No action needed. If you share NemoClaw debug output, verify that no secrets appear in the collected diagnostics. | - - - -### Memory Secret Scanner - -The NemoClaw plugin blocks the agent from writing likely secrets (API keys, tokens, private keys) into persistent memory files. -The scanner intercepts `Write`, `Edit`, and similar tool calls targeting memory and workspace paths before they reach disk. - -| Aspect | Detail | -|---|---| -| Default | Enabled. The plugin registers a `before_tool_call` hook that scans for 14 high-confidence secret patterns. | -| What it covers | Three path classifiers, all enforced through `isMemoryPath()`, plus credential-shaped text such as provider API keys, OpenAI project keys with `sk-proj-` prefixes, and Slack app-level `xapp-` tokens. The path classifiers are: (1) absolute `MEMORY_PATH_SEGMENTS` such as `/.openclaw/memory/`, `/.openclaw/workspace/`, `/.openclaw/agents/`, `/.openclaw/skills/`, `/.openclaw/hooks/`, `/.openclaw/credentials/`, `/.openclaw/openclaw.json`, `/.nemoclaw/`; (2) canonical workspace basenames in `MEMORY_BASENAMES` (`IDENTITY.md`, `MEMORY.md`, `SOUL.md`, `USER.md`, `AGENTS.md`) matched regardless of the surrounding path; and (3) lexically-normalized workspace-relative writes matching `MEMORY_RELATIVE_PREFIXES` (`.openclaw/`, `.nemoclaw/`, `memory/`) or named workspace daily memory paths, for embedded-fallback mode where the host's path resolver is unavailable. | -| What you can change | This is not a user-facing knob. The plugin enforces it automatically. | -| Risk if relaxed | Without scanning, the agent could persist API keys or tokens in memory files that survive across sessions and backups. | -| Recommendation | No action needed. If a write is blocked, the agent receives an actionable error listing the detected patterns. | - - - - -### Memory Secret Scanner - -Hermes does not use the OpenClaw NemoClaw plugin memory scanner. -Keep secrets in environment variables or OpenShell providers, and avoid writing raw credentials to Hermes state files or workspace content. - - - - -### Memory Secret Scanner - -Deep Agents does not use the OpenClaw NemoClaw plugin memory scanner. -The managed `dcode` launchers reject credential-shaped environment values and upstream auth files before startup, but Deep Agents memory and skill files remain user-authored content. -Keep secrets in OpenShell providers and avoid writing raw credentials to `/sandbox/.deepagents`, project `.deepagents/`, or skill files. - - +Review runtime-specific gateway access, dashboard exposure where applicable, secret redaction, and memory scanning in [Understand Gateway and Secret Controls](./security-controls/gateway-authentication-controls). ## Inference Controls diff --git a/docs/security/filesystem-controls.mdx b/docs/security/filesystem-controls.mdx new file mode 100644 index 00000000000..1ad29b2ce46 --- /dev/null +++ b/docs/security/filesystem-controls.mdx @@ -0,0 +1,203 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Understand Filesystem Controls" +sidebar-title: "Filesystem Controls" +description: "Review NemoClaw filesystem defaults, writable paths, agent state protections, and Landlock enforcement." +description-agent: "Explains NemoClaw filesystem controls and their security trade-offs. Use when reviewing writable paths, agent state protection, or Landlock enforcement." +keywords: ["nemoclaw filesystem controls", "landlock", "sandbox writable paths"] +content: + type: "concept" +--- +NemoClaw restricts which paths the agent can read and write, protecting system binaries, configuration files, and gateway credentials. + +OpenShell covers additional filesystem enforcement details, including `hard_requirement` compatibility mode for Landlock and policy path validation rules. +Refer to the [Filesystem Controls](https://docs.nvidia.com/openshell/latest/security/best-practices.html#filesystem-controls) section of the OpenShell Security Best Practices. + +## Read-Only System Paths + +The container mounts system directories read-only to prevent the agent from modifying binaries, libraries, or configuration files. + +| Aspect | Detail | +|---|---| +| Default | `/usr`, `/lib`, `/proc`, `/dev/urandom`, `/app`, `/etc`, `/var/log`, and `/var/lib/dpkg` are read-only. | +| What you can change | Add or remove paths in the `filesystem_policy.read_only` section of the policy file. | +| Risk if relaxed | Making `/usr` or `/lib` writable lets the agent replace system binaries (such as `curl` or `node`) with trojanized versions. Making `/etc` writable lets the agent modify DNS resolution, TLS trust stores, or user accounts. | +| Recommendation | Never make system paths writable. If the agent needs a writable location for generated files, use a subdirectory of `/sandbox`. | + +## Agent Config Directory + + + +The `/sandbox/.openclaw` directory contains the OpenClaw gateway configuration (model routing, CORS settings, channel config). +The current entrypoint reads the gateway auth token from OpenClaw config when present, exports it as `OPENCLAW_GATEWAY_TOKEN`, and writes it to `/tmp/nemoclaw-proxy-env.sh` so interactive sandbox sessions can reach the gateway through system-wide shell hooks. + +In root mode, the gateway process still runs as the separate `gateway` user, but the token is intentionally available to sandbox shells for local gateway access. + +Writable agent state such as plugins, skills, hooks, and workspace metadata lives directly under `/sandbox/.openclaw`. + +By default, this directory starts writable so the agent can manage its own config, install skills, and write to standard home-directory paths natively. +For sensitive workloads, use a reviewed host-side immutability workflow after initial setup so the sandbox user cannot change config or high-risk state entry points. + +The immutability workflow derives its path plan from the selected agent manifest. +For OpenClaw, it locks `agents`, `canvas`, `cron`, `devices`, `extensions`, `hooks`, `memory`, `plugins`, `profiles`, `skills`, `telegram`, `wechat`, `whatsapp`, `workspace`, and `workspace-*` directories to `root:sandbox` and removes group and world write access. + +The root-only helper traverses from opened directory descriptors with no-follow semantics instead of using recursive pathname `chown` or `chmod`. +Read-only preflight and unlock operations reject unsafe external symlinks, hardlinks, special files, cross-device entries, and entries that race the traversal without modifying them. + +After the top-level config binding is frozen, lockdown makes containment monotonic. +It removes unsafe symlinks, special entries, and protected-root names that are not directories through descriptor-relative operations without following their targets. + +For protected regular files, lockdown publishes a fresh inode, severing hardlinks while preserving file content, read/execute mode, timestamps, and supported extended attributes; this also revokes write authority held through a descriptor opened before `shields up`. + +The OpenClaw gateway (a member of the `sandbox` group) keeps read access to plugin and agent code; the sandbox user can no longer write them. + +The same workflow locks the secret-bearing `credentials` and `identity` directories. +The guard sets each confidentiality root to `root:sandbox 0710`, including a non-empty `credentials` directory. +It sets every nested directory and file to `root:root` and removes all group and world permission bits. + +The sandbox group cannot list, create, or remove entries in a confidentiality root, and neither the sandbox user nor gateway can read stored secrets. +They can inspect metadata for a direct child only when they already know its name. +Probing a missing direct child, such as the legacy `credentials/oauth.json`, returns `ENOENT` instead of `EACCES`. + +Restoring the mutable-default posture returns those directories to `sandbox:sandbox 2770`. + +For plan-aware current images and host-injected transitions, each agent manifest declares only its own protected paths, confidential paths, dynamic prefixes, and writable subpaths. +The lock helper applies only that selected manifest plan and skips declared paths that are not present. + +Historical OpenClaw and Hermes images that have a bundled helper but no generated plan use the helper's reviewed legacy inventory until the sandbox is rebuilt. +State directories without a Shields declaration remain mutable. + +Inside a locked tree, the helper keeps each `agents//sessions/` root at `sandbox:sandbox 2770` so the OpenClaw TUI can create and write session metadata under an otherwise root-owned parent. +After containment, when an agent directory has no `sessions` entry, lockdown creates that carve-out root. + +An agent booting for the first time under an active lock can then write sessions. +It validates the carve-out root but deliberately does not traverse or rewrite live session descendants. + +Cross-device entries, detected traversal races, or failures to remove or replace an unsafe entry make lockdown fail closed with the exact path and reason. + +- **DAC permissions (default).** + The sandbox user owns `/sandbox/.openclaw` with mode `2770` (setgid `sandbox:sandbox`) and `openclaw.json` with mode `660`, so the agent and its group can read and write config directly. + A reviewed host-side immutability workflow should compare the intended ownership and mode with the live sandbox filesystem before treating the config tree as locked. +- **Config integrity hash.** + The image includes a SHA256 hash of `openclaw.json`. + In the default mutable state, `.config-hash` is sandbox-owned and is not a tamper-proof trust anchor, so startup does not fail closed on that hash. + When the hash is root-owned and read-only, startup enforces it and refuses to start if the hash does not match. +- **Content integrity seal.** + A clean immutable config lock can capture a SHA-256 seal of `openclaw.json` and other locked files into host-side state. + Verification recomputes hashes inside the sandbox and surfaces drift on mismatch, so a host-root tamper that flips permissions back to `444 root:root` after rewriting the file is still flagged. + Sandboxes locked before the seal landed have no recorded hash; permission-only verification cannot prove their bytes match the image original, so the seal is **not** a retroactive proof of integrity for legacy state. + The same limitation applies when the locked file set grew after the existing seal was captured. + Rebuild the sandbox for a known-good baseline before trusting a new seal. +- **Gateway token environment.** + The gateway exports `OPENCLAW_GATEWAY_TOKEN` and writes it to `/tmp/nemoclaw-proxy-env.sh` for interactive sandbox sessions. + Keep this in mind when deciding whether a workload should run with mutable config or an immutable config posture. + +| Aspect | Detail | +|---|---| +| Default | The sandbox keeps `/sandbox/.openclaw` writable (`2770 sandbox:sandbox`), sets `openclaw.json` to `660 sandbox:sandbox`, lets the agent manage state directly, and has the gateway place `OPENCLAW_GATEWAY_TOKEN` in `/tmp/nemoclaw-proxy-env.sh` for interactive shells. | +| What you can change | Apply a reviewed host-side immutability workflow to lock config and state directories with DAC permissions and the immutable flag where available. | +| Risk of default | A writable `.openclaw` directory lets the agent modify its own gateway config: disabling CORS or redirecting inference to an attacker-controlled endpoint. | +| Recommendation | For always-on assistants handling sensitive workloads, lock config after initial setup. For development workflows, the writable default is appropriate. | + + + + +The `/sandbox/.hermes` directory contains Hermes runtime configuration, generated environment settings, logs, platform state, and durable database state. +NemoClaw writes `config.yaml` and `.env` during onboarding and rebuilds. +Direct edits to these files can be overwritten when NemoClaw regenerates the image. + +Hermes also stores runtime state such as `state.db`, logs, and platform sessions under the `.hermes` tree. +Messaging sessions such as WhatsApp pairing can remain mutable by design so they survive rebuilds. + +For plan-aware current images, the Shields workflow derives the Hermes lock plan from its agent manifest. +Historical Hermes images that have a bundled helper but no generated plan use the helper's reviewed legacy inventory until the sandbox is rebuilt. + +It locks `cron`, `hooks`, `platforms`, `plugins`, `profiles`, `skills`, `skins`, `weixin`, and `workspace` to `root:sandbox`. +The `profiles/dashboard-home` carve-out remains `sandbox:sandbox 0700`, and the guard does not traverse or rewrite its descendants. +It locks the `pairing` confidentiality root to `root:sandbox 0710`. +Hermes runtime directories without a Shields declaration remain mutable. + +The shared state-directory guard applies the manifest declaration to `pairing` on current Hermes images. +On historical images, the reviewed legacy inventory also treats present `credentials` and `identity` directories as confidentiality roots. + +The guard sets the root to `root:sandbox 0710`, keeps it traversable but unlistable to the sandbox group, and sets every descendant to `root:root` with no group or world permission bits. +As a result, a known-name probe for a missing direct child returns `ENOENT`, while directory listing, nested traversal, and protected-file reads return `EACCES`. + +| Aspect | Detail | +|---|---| +| Default | The Hermes config tree contains NemoClaw-generated config plus mutable runtime state. | +| What you can change | Use host-side NemoClaw commands for durable model, provider, messaging, and policy changes; inspect files directly only for debugging. | +| Risk of direct edits | Direct edits to generated config can drift from the host registry and may be lost on rebuild. | +| Recommendation | For sensitive workloads, keep generated config under NemoClaw control and back up Hermes state before destructive operations. | + + + + +The `/sandbox/.deepagents` directory contains Deep Agents Code runtime state and NemoClaw-generated configuration. +NemoClaw writes `config.toml` during onboarding and rebuilds. +Direct edits to this file can be overwritten when NemoClaw regenerates the managed inference route. + +The managed Deep Agents image deliberately omits raw provider and service credentials from generated configuration. +Credential-bearing files such as `.deepagents/.env` and user-authored `.deepagents/.mcp.json` are treated as user-managed files and are not included in NemoClaw snapshots. + +The managed `.deepagents/.nemoclaw-mcp.json` projection contains OpenShell placeholders and is reconstructed from host-side registry state. + +The Shields workflow derives the Deep Agents lock plan from its agent manifest. +The `agent/skills` declaration locks the top-level `agent` directory, and the `skills` declaration locks the top-level `skills` directory. +The `.state` directory remains mutable. + +| Aspect | Detail | +|---|---| +| Default | The Deep Agents config tree contains NemoClaw-generated `config.toml`, managed MCP projection state, and mutable Deep Agents memory and skill state. | +| What you can change | Use host-side NemoClaw commands for durable model, provider, managed MCP, and policy changes; inspect or edit memory and skills through `dcode` or direct file access when appropriate. | +| Risk of direct edits | Direct edits to generated config can drift from the host registry and may be lost on rebuild. Storing credentials in `.deepagents/.env` or user `.mcp.json` moves them outside the managed credential boundary. | +| Recommendation | Keep generated config under NemoClaw control. Use OpenShell providers and NemoClaw MCP commands for credentials, and back up Deep Agents state before destructive operations. | + + + +## Writable Paths + +The agent has read-write access to `/sandbox`, `/tmp`, `/dev/null`, and `/dev/pts`. + +| Aspect | Detail | +|---|---| +| Default | `/sandbox` (agent workspace), `/tmp` (temporary files), `/dev/null`, and `/dev/pts` (the devpts pseudo-terminal directory, required so PTY-based tools such as `tmux`, `script`, and interactive shells can allocate a terminal). | +| What you can change | Add additional writable paths in `filesystem_policy.read_write`. | +| Risk if relaxed | Each additional writable path expands the agent's ability to persist data and potentially modify system behavior. Adding `/var` lets the agent write to log directories. Adding `/home` gives access to other user directories. | +| Recommendation | Keep writable paths to `/sandbox` and `/tmp`. If the agent needs a persistent working directory, create a subdirectory under `/sandbox`. | + +## Landlock LSM Enforcement + +Landlock is a Linux Security Module that enforces filesystem access rules at the kernel level. + + + +| Aspect | Detail | +|---|---| +| Default | `compatibility: best_effort`. The entrypoint applies Landlock rules when the kernel supports them and silently skips them on older kernels. | +| What you can change | This is a NemoClaw default, not a user-facing knob. | +| Risk if relaxed | On kernels without Landlock support (pre-5.13), filesystem restrictions rely solely on container mount configuration, which is less granular. | +| Recommendation | Run on a kernel that supports Landlock (5.13+). Ubuntu 22.04 LTS and later include Landlock support. | + + + + +| Aspect | Detail | +|---|---| +| Default | `compatibility: best_effort`. The entrypoint applies Landlock rules when the kernel supports them and silently skips them on older kernels. | +| What you can change | This is a NemoClaw default, not a user-facing knob. | +| Risk if relaxed | On kernels without Landlock support (pre-5.13), filesystem restrictions rely solely on container mount configuration, which is less granular. | +| Recommendation | Run on a kernel that supports Landlock (5.13+). Ubuntu 22.04 LTS and later include Landlock support. | + + + + +| Aspect | Detail | +|---|---| +| Default | `compatibility: strict`. Deep Agents sandbox startup fails closed when OpenShell cannot enforce the managed filesystem policy. | +| What you can change | This is a NemoClaw Deep Agents invariant, not a user-facing knob. | +| Risk if relaxed | Silent Landlock degradation would leave the terminal coding harness with weaker filesystem isolation while still reporting a successful sandbox. | +| Recommendation | Run Deep Agents on a kernel and runtime that support Landlock enforcement. Rebuild or move hosts if startup reports an enforcement failure. | + + diff --git a/docs/security/gateway-authentication-controls.mdx b/docs/security/gateway-authentication-controls.mdx new file mode 100644 index 00000000000..9e5af6add4e --- /dev/null +++ b/docs/security/gateway-authentication-controls.mdx @@ -0,0 +1,206 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Understand Gateway and Secret Controls" +sidebar-title: "Gateway and Secrets" +description: "Review runtime-specific gateway access and the shared secret-redaction and memory-scanning controls." +description-agent: "Explains runtime-specific gateway access and shared secret-handling controls. Use when reviewing dashboard exposure, device pairing, secret redaction, or memory scanning." +keywords: ["nemoclaw gateway security", "dashboard security", "secret redaction"] +content: + type: "concept" +--- +NemoClaw applies gateway access controls when the selected agent runtime exposes an in-sandbox gateway or dashboard. +CLI secret redaction and runtime-specific memory guidance apply across guide variants. + + +LangChain Deep Agents Code has no in-sandbox agent gateway or dashboard, so device pairing, bind, and dashboard controls do not apply. +The shared secret-handling controls below still apply. + + + + +The OpenClaw gateway authenticates devices that connect to the Control UI dashboard. +NemoClaw hardens these defaults at image build time. + +## Device Authentication + +Device authentication requires each connecting device to go through a pairing flow before it can interact with the gateway. + +| Aspect | Detail | +|---|---| +| Default | The base Dockerfile enables device authentication for loopback dashboards. Standard onboarding currently applies a managed compatibility opt-out for immediate dashboard access. NemoClaw also disables device authentication for non-loopback `CHAT_UI_URL` values. | +| What you can change | Outside managed onboarding, set `NEMOCLAW_DISABLE_DEVICE_AUTH=1` only as a deliberate build-time opt-out. The setting and its managed-vs-operator provenance are baked into `openclaw.json` audit metadata and the config is verified by hash at startup. | +| Risk if relaxed | Disabling device auth allows any device on the network to connect to the gateway without proving identity. This is dangerous when combined with LAN-bind changes or cloudflared tunnels in remote deployments, resulting in an unauthenticated, publicly reachable dashboard. | +| Recommendation | Prefer loopback access or SSH port forwarding so device authentication stays enabled. If a browser-only remote dashboard requires the compatibility setting, use HTTPS and restrict who can reach the dashboard. | + +## Gateway Bind Address + +NemoClaw binds the OpenShell gateway to loopback by default. + +| Aspect | Detail | +|---|---| +| Default | `NEMOCLAW_GATEWAY_BIND_ADDRESS=127.0.0.1`. | +| What you can change | Keep Docker-driver gateways on loopback. Set `NEMOCLAW_DASHBOARD_BIND=0.0.0.0` during onboarding and on later `connect` calls for remote dashboard/API access. Recreate a local-only sandbox before changing it to a remote bind. | +| Risk if relaxed | Other hosts on the network may be able to reach the OpenShell gateway. NemoClaw rejects wildcard Docker-driver gateway binds while gateway JWT auth is active. | +| Recommendation | Keep the gateway loopback default and expose only the dashboard forward when remote access is needed. | + +## Gateway Compatibility Container + +On Linux hosts whose glibc is older than the OpenShell gateway binary requires, NemoClaw can run `openshell-gateway` in a Docker compatibility container so the Docker-driver gateway still starts. This path requires the explicit opt-in `NEMOCLAW_OPENSHELL_GATEWAY_CONTAINER_PATCH=1`. + +| Aspect | Detail | +|---|---| +| Default | NemoClaw does not auto-enable the compatibility container on ABI mismatch. If `NEMOCLAW_OPENSHELL_GATEWAY_CONTAINER_PATCH=1` is set, the container keeps the main gateway listener on `127.0.0.1`, uses host networking so OpenShell computes the same Docker bridge callback addresses as a host-side gateway, mounts the Docker socket read-only, drops Linux capabilities, sets `no-new-privileges`, and publishes no extra Docker ports. | +| What you can change | Opt in with `NEMOCLAW_OPENSHELL_GATEWAY_CONTAINER_PATCH=1`, keep the path disabled with `NEMOCLAW_OPENSHELL_GATEWAY_CONTAINER_PATCH=0`, or run on a host/OpenShell build combination where the gateway binary launches directly. | +| Risk if relaxed | The Docker socket remains a privileged host API even when bind-mounted read-only. Treat this mode as equivalent to trusting the host user that can drive Docker, and do not enable it on untrusted shared hosts. | +| Recommendation | Prefer a host with glibc 2.39 or newer, which OpenShell 0.0.99 supports directly, and use the compatibility container only as an explicit local bridge on an older trusted host. | + +Refer to [OpenShell Gateway Compatibility Review](../openshell-0.0.72-compatibility-review) for the unchanged compatibility-container source-of-truth boundaries. + +## Insecure Auth Derivation + +The `allowInsecureAuth` setting controls whether the gateway permits non-HTTPS authentication. + +| Aspect | Detail | +|---|---| +| Default | Derived from the `CHAT_UI_URL` scheme at build time. When the URL uses `http://` (local development), insecure auth is allowed. When it uses `https://` (remote or production), insecure auth is blocked. | +| What you can change | This is derived automatically from `CHAT_UI_URL`. Set `CHAT_UI_URL` to an `https://` URL to enforce secure auth. | +| Risk if relaxed | Allowing insecure auth over HTTPS defeats the purpose of TLS, because authentication tokens transit in cleartext. | +| Recommendation | Use `https://` for any deployment accessible beyond `localhost`. The default local URL (`http://127.0.0.1:18789`) correctly allows insecure auth for local development. | + +OpenClaw's security audit keeps NemoClaw-managed loopback `allowInsecureAuth` findings and provenance-known loopback device-auth opt-out findings visible as accepted findings instead of counting them as unexplained active findings. + +Device-auth findings record whether the opt-out came from NemoClaw's managed onboarding compatibility behavior or an operator-provided `NEMOCLAW_DISABLE_DEVICE_AUTH=1`; an opt-out with missing provenance remains active. + +For audit reporting, NemoClaw treats a non-loopback `CHAT_UI_URL`, an onboard-time `NEMOCLAW_DASHBOARD_BIND=0.0.0.0`, or WSL's default all-interface dashboard forward as remote dashboard exposure. +For an explicit `NEMOCLAW_DASHBOARD_BIND=0.0.0.0` bind, use the same setting on later `connect` calls. + +If the sandbox was created without that explicit setting, NemoClaw refuses the remote forward until you recreate it with `NEMOCLAW_DASHBOARD_BIND=0.0.0.0 $$nemoclaw onboard --recreate-sandbox`; this keeps the generated audit state aligned with the host exposure state. + +On WSL, the ready summary still uses a loopback URL, but the generated audit configuration leaves the device-auth and insecure-auth findings active. +For an explicit remote bind with a loopback `CHAT_UI_URL`, NemoClaw disables device auth and enables OpenClaw's Host-header origin fallback because the browser's remote origin is not known at image-build time. + +Both settings expand access and must remain explicit; use HTTPS or an SSH local forward when possible. + +In that state, NemoClaw does not add the loopback-only audit suppressions, so the resulting device-auth, insecure-auth, and Host-header fallback findings remain active. +The generated configuration uses exact audit check IDs and flag details, records why each setting is present, and leaves the original severity and remediation under `suppressedFindings` in JSON output. + +The audit also reports that suppressions are active so you can review the accepted risk. +These suppressions change audit reporting only. +They do not make either flag safe, weaken enforcement, or suppress unrelated findings. + +Review the accepted findings and their recorded reasons: + +```bash +openclaw security audit --json | jq '.suppressedFindings' +``` + +Remove the underlying risky condition when dashboard compatibility no longer requires it. + +Remove these suppressions only after the pinned OpenClaw audit contract test proves that OpenClaw natively classifies intentional loopback development HTTP without them, or after NemoClaw onboarding defaults `CHAT_UI_URL` to `https://localhost` with a generated local certificate. + +Regression contracts: `test/generate-openclaw-config-security-audit.test.ts` locks generated suppression scope, `test/openclaw-security-audit-suppressions-real.test.ts` locks the pinned OpenClaw check IDs and details, and `test/e2e/live/dashboard-remote-bind.test.ts` proves a clean-host remote bind leaves all three risky findings active. + +The preceding removal condition applies to all three contracts. + +## Auto-Pair Client Allowlist + +The auto-pair watcher automatically approves device pairing requests from recognized clients, so you do not need to manually approve the Control UI. + +| Aspect | Detail | +|---|---| +| Default | Startup auto-pairing and `connect`-time approval share one policy. NemoClaw approves devices only when `clientId` is `cli`, `openclaw-cli`, or `openclaw-control-ui`, and only for `operator.pairing`, `operator.read`, and `operator.write` scopes. An allowlisted `clientMode` alone is never sufficient; all other clients or scopes are rejected and logged. | +| What you can change | This is not a user-facing knob. The allowlist is defined by NemoClaw's OpenClaw device-approval helper. | +| Risk if relaxed | Approving all device types without validation lets rogue or unexpected clients pair with the gateway unchallenged. | +| Recommendation | No action needed. NemoClaw handles this automatically at startup and during `connect` for late scope upgrades. If you see `[auto-pair] rejected unknown client=...` in the logs, investigate the source of the unexpected connection. | + +### Approve Administrative Scopes Manually + +NemoClaw automatically approves only the `operator.pairing`, `operator.read`, and `operator.write` scopes. +It never automatically approves `operator.admin`. +Operations that require that scope, such as creating a cron job, need your explicit approval. + +From the host, open the prepared connect shell: + +```bash +$$nemoclaw connect +``` + +In that shell, run the administrative command once to create the pending request, and note the exact `requestId` in the failure. +Then inspect the pending requests: + +```bash +openclaw devices list --json +``` + +Find that exact `requestId`, and verify that its client, device, and requested scopes match the operation you just attempted. +Approve that request by its `requestId`: + +```bash +openclaw devices approve +``` + +Retry the original administrative command after the approval succeeds. + + +Approve only the exact `requestId` emitted by your command and only the client, device, and scopes you expect. +Do not approve an unexpected client or an unrelated `operator.admin` request. + + + + + +Hermes exposes an OpenAI-compatible API on the forwarded Hermes port and can optionally expose the native Hermes dashboard. +Do not publish those endpoints on shared or public networks unless you put them behind your own access controls. + +NemoClaw still keeps provider credentials in OpenShell and routes model traffic through `inference.local`. +Generated Hermes runtime files use OpenShell resolver placeholders for managed-tool and messaging credentials. + +Hermes startup rejects raw secret-shaped values in sandbox-visible environment or config fields, while allowing empty values, migration sentinels, OpenShell resolver placeholders, and expected Slack placeholder forms. + + + +## CLI Secret Redaction + +The CLI automatically redacts secret patterns (API keys, bearer tokens, provider credentials) from command output and error messages before logging them. + +| Aspect | Detail | +|---|---| +| Default | Enabled. The runner redacts secrets from stdout, stderr, and thrown error messages. | +| What you can change | This is not a user-facing knob. The CLI enforces it on all command output paths. | +| Risk if relaxed | Without redaction, secrets could appear in terminal scrollback, log files, or debug output shared in bug reports. | +| Recommendation | No action needed. If you share NemoClaw debug output, verify that no secrets appear in the collected diagnostics. | + + + +## Memory Secret Scanner + +The NemoClaw plugin blocks the agent from writing likely secrets (API keys, tokens, private keys) into persistent memory files. +The scanner intercepts `Write`, `Edit`, and similar tool calls targeting memory and workspace paths before they reach disk. + +| Aspect | Detail | +|---|---| +| Default | Enabled. The plugin registers a `before_tool_call` hook that scans for 14 high-confidence secret patterns. | +| What it covers | Three path classifiers, all enforced through `isMemoryPath()`, plus credential-shaped text such as provider API keys, OpenAI project keys with `sk-proj-` prefixes, and Slack app-level `xapp-` tokens. The path classifiers are: (1) absolute `MEMORY_PATH_SEGMENTS` such as `/.openclaw/memory/`, `/.openclaw/workspace/`, `/.openclaw/agents/`, `/.openclaw/skills/`, `/.openclaw/hooks/`, `/.openclaw/credentials/`, `/.openclaw/openclaw.json`, `/.nemoclaw/`; (2) canonical workspace basenames in `MEMORY_BASENAMES` (`IDENTITY.md`, `MEMORY.md`, `SOUL.md`, `USER.md`, `AGENTS.md`) matched regardless of the surrounding path; and (3) lexically-normalized workspace-relative writes matching `MEMORY_RELATIVE_PREFIXES` (`.openclaw/`, `.nemoclaw/`, `memory/`) or named workspace daily memory paths, for embedded-fallback mode where the host's path resolver is unavailable. | +| What you can change | This is not a user-facing knob. The plugin enforces it automatically. | +| Risk if relaxed | Without scanning, the agent could persist API keys or tokens in memory files that survive across sessions and backups. | +| Recommendation | No action needed. If a write is blocked, the agent receives an actionable error listing the detected patterns. | + + + + +## Memory Secret Scanner + +Hermes does not use the OpenClaw NemoClaw plugin memory scanner. +Keep secrets in environment variables or OpenShell providers, and avoid writing raw credentials to Hermes state files or workspace content. + + + + +## Memory Secret Scanner + +Deep Agents does not use the OpenClaw NemoClaw plugin memory scanner. +The managed `dcode` launchers reject credential-shaped environment values and upstream auth files before startup, but Deep Agents memory and skill files remain user-authored content. +Keep secrets in OpenShell providers and avoid writing raw credentials to `/sandbox/.deepagents`, project `.deepagents/`, or skill files. + + diff --git a/docs/security/process-controls.mdx b/docs/security/process-controls.mdx new file mode 100644 index 00000000000..4eb567141d9 --- /dev/null +++ b/docs/security/process-controls.mdx @@ -0,0 +1,237 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Understand Process Controls" +sidebar-title: "Process Controls" +description: "Review NemoClaw process capabilities, resource limits, runtime identity, and image hardening." +description-agent: "Explains NemoClaw process controls and their security trade-offs. Use when reviewing capability drops, process limits, runtime identity, or image hardening." +keywords: ["nemoclaw process controls", "capability drops", "sandbox process limits"] +content: + type: "concept" +--- +NemoClaw limits the capabilities, user privileges, and resource quotas available to processes inside the sandbox. + +OpenShell enforces additional process-level controls not covered here, including seccomp BPF socket domain filters and a specific enforcement application order (namespace entry, privilege drop, Landlock, seccomp). +Refer to the [Process Controls](https://docs.nvidia.com/openshell/latest/security/best-practices.html#process-controls) section of the OpenShell Security Best Practices. + +## 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. + +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`. +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. + +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. + +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)). + + +For additional protection, pass `--cap-drop=ALL` with `docker run` or Compose. +Refer to [Review Sandbox Hardening](../../manage-sandboxes/configure-sandboxes/review-sandbox-hardening). + + +| 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. | +| 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. | + +## Gateway Process Isolation + +Gateway and agent UID isolation depends on the container process topology. +A direct root-entrypoint container runs the gateway as the separate `gateway` user and the agent as the `sandbox` user. +An OpenShell-managed container has OpenShell as PID 1 and launches nonroot `nemoclaw-start`, so the supervisor, gateway, and agent all use the `sandbox` UID. + +| Aspect | Detail | +|---|---| +| Default | Direct root entrypoints use `setpriv` for gateway UID isolation. The OpenShell-managed topology runs the gateway and agent under the same sandbox UID because `no-new-privileges` prevents the nonroot entrypoint from changing users. | +| What you can change | This is not a user-facing knob. The selected container topology determines whether the entrypoint can step down from root to the gateway UID. | +| Risk if relaxed | A same-UID agent can signal peer processes and can attempt to imitate the expected gateway process shape. The root managed controller prevents PID-reuse mistakes, but it cannot prove provenance against a malicious same-UID process or provide the direct root-entrypoint restart seal for mutable config. | +| Recommendation | Use a direct root-entrypoint deployment when separate gateway and agent UIDs are required. Treat the managed controller as authenticated lifecycle and exact-target safety, not as a same-UID provenance boundary. | + +## No New Privileges + +The `no-new-privileges` flag prevents processes from gaining additional privileges through setuid binaries or capability inheritance. + +| Aspect | Detail | +|---|---| +| Default | OpenShell sets `PR_SET_NO_NEW_PRIVS` using `prctl()` inside the sandbox process as part of the seccomp filter setup. The NemoClaw Compose example also shows the equivalent `security_opt: no-new-privileges:true` setting. | +| What you can change | OpenShell's seccomp path enforces this inside the sandbox. It is not a user-facing knob. | +| Risk if relaxed | Without this flag, a compromised process could execute a setuid binary to escalate to root inside the container, then attempt container escape techniques. | +| Recommendation | No action needed. OpenShell enforces this automatically when the sandbox network policy is active. In the OpenShell-managed topology, this flag also means the nonroot entrypoint and gateway remain under the sandbox UID. | + +## Process Limit + +A process limit caps the number of processes the sandbox user can spawn. +The entrypoint sets both soft and hard limits using `ulimit -u 512`. +This behavior is best effort. +If the container runtime restricts `ulimit` modification, the entrypoint logs a security warning and continues without the limit. + +| Aspect | Detail | +|---|---| +| Default | 512 processes (`ulimit -u 512`), best-effort. | +| What you can change | Increase or decrease the limit with `--ulimit nproc=N:N` in `docker run` or the `ulimits` section in Compose. The runtime-level ulimit takes precedence over the entrypoint's setting. | +| Risk if relaxed | Removing or raising the limit makes the sandbox vulnerable to fork-bomb attacks, where a runaway process spawns children until the host runs out of resources. If the entrypoint cannot set the limit (logs `[SECURITY] Could not set soft/hard nproc limit`), the container runs without process limits. | +| Recommendation | Keep the default at 512. If the agent runs workloads that spawn many child processes (such as parallel test runners), increase to 1024 and monitor host resource usage. If the entrypoint logs a warning about ulimit restrictions, set the limit through the container runtime instead. | + +## Open File Descriptor Limit + +An open file descriptor limit caps the number of files, sockets, and pipes the sandbox user can hold open at once. +The entrypoint sets both soft and hard limits using `ulimit -n 65536`. +This behavior is best effort. +If the container runtime restricts `ulimit` modification, the entrypoint logs a security warning and continues without the limit. + +| Aspect | Detail | +|---|---| +| Default | 65536 open files, soft and hard (`ulimit -n 65536`), best-effort. | +| What you can change | Increase or decrease the limit with `--ulimit nofile=N:N` in `docker run` or the `ulimits` section in Compose. The runtime-level ulimit takes precedence over the entrypoint's setting. | +| Risk if relaxed | Without this cap, the sandbox inherits the Docker daemon default (`nofile` ~1048576). A runaway or hostile process can then open file descriptors until it exhausts them, causing a denial of service that can starve the gateway, the agent, or the host of file handles. If the entrypoint cannot set the limit (logs `[SECURITY] Could not set soft/hard nofile limit`), the container runs without a file-descriptor cap. For more information, refer to [#4527](https://github.com/NVIDIA/NemoClaw/issues/4527). | +| Recommendation | Keep the default at 65536. If the agent legitimately keeps many connections or files open, raise it deliberately and monitor host file-descriptor usage. If the entrypoint logs a warning about ulimit restrictions, set the limit through the container runtime instead. | + + + +## Deep Agents Resource Limit Enforcement + +Managed Deep Agents uses stricter enforcement than the best-effort entrypoint behavior described above. +The managed Deep Agents image applies the 512-process and 65,536-file-descriptor caps to the long-running sandbox entrypoint tree and to direct managed `dcode` launches. + +During Docker-driver onboarding, NemoClaw also configures the container with exact `nproc=512:512` and `nofile=65536:65536` limits so the managed entrypoint and fresh exec or connect processes start under the same hard caps. +The container-level limits and managed startup command remain in effect when you stop and start the sandbox or restart the OpenShell gateway. + +It also applies and verifies the caps in Bash login and interactive shells because fresh `openshell sandbox exec` and connect shells do not inherit the dcode entrypoint child's lowered limits. + +For managed Deep Agents, successful verification requires both the soft and hard limits to equal 512 processes and 65,536 file descriptors; a lower inherited file-descriptor default such as 1,024 is not accepted as successful hardening. + +If the image-baked resource-limit helper is missing or the effective limits do not match policy after hardening, the Deep Agents entrypoint and direct managed launcher refuse to start. +The entrypoint and launcher complete this verification before proxy setup or user-supplied commands run. + +A login or interactive shell remains available when the helper is missing or its limits cannot be verified, but it prints `[SECURITY] Sandbox resource limits were NOT hardened for this shell.` + +OpenShell creates those fresh exec and connect processes outside the entrypoint tree, so an image layer cannot make them inherit the entrypoint child's lowered limits. +The shell compatibility exception can be removed when OpenShell guarantees that every exec and connect process starts under enforced caps or exposes a fail-closed resource-limit contract. + +For custom container launches outside NemoClaw's managed Docker-driver onboarding path, set hard `nproc` and `nofile` limits at the container runtime when you require fail-closed enforcement. + +## Deep Agents Thread Auto-Approval Capability + +Managed Deep Agents sandboxes separate the host-configured capability from the active approval state of each TUI thread. +The default `disabled` mode keeps the TUI auto-approval choice and `dcode -y` unavailable. + +An operator can select `thread-opt-in` through a named transactional rebuild, but each thread still requires an explicit TUI choice or `dcode -y` invocation before tool calls run without further confirmation. + +NemoClaw stores the configured mode in a root-owned, mode `0444` image file rather than trusting runtime environment variables. +A missing, malformed, symlinked, writable, unreadable, or incorrectly owned capability file resolves to `disabled`. +Ambient `NEMOCLAW_DCODE_AUTO_APPROVAL*` values cannot enable the capability. + +When a thread activates auto-approval, the TUI shows the upstream active-state indicator and prints a warning. +NemoClaw clears that active state for a new process, `/clear`, `/force-clear`, a thread switch or resume, and an agent switch. +The host-side `status` command reports only the configured capability because it does not attest to the current state of a specific TUI thread. + +| Aspect | Detail | +|---|---| +| Default | `disabled`. Interactive tool calls keep their approval prompts, and thread auto-approval cannot be selected. | +| What you can change | Use `--dcode-auto-approval thread-opt-in` during a named managed Deep Agents rebuild. Use `--dcode-auto-approval disabled` in another rebuild to revoke the capability. | +| Risk if enabled | A prompt injection, untrusted repository, or mistaken plan can cause tool calls, including shell commands, to run without another human confirmation for the rest of the active thread. | +| Remaining controls | OpenShell egress policy, credential isolation and rewriting, the managed inference route, managed MCP validation, filesystem and process controls, and the other managed runtime restrictions remain active. | +| Recommendation | Keep `disabled` for sensitive or unfamiliar work. Enable `thread-opt-in` only for bounded tasks in a reviewed workspace, watch the active-state indicator, and start a new thread or rebuild with `disabled` when unattended tool execution is no longer acceptable. | + + +Treat `thread-opt-in` as permission for unattended shell execution inside the sandbox, not as a policy bypass. +The sandbox boundary limits where commands run and what external resources they can reach, but it does not make an automatically approved command harmless to writable workspace data. + + +## Headless Deep Agents Approval Boundary + +Interactive `dcode` sessions keep destructive tools behind the Deep Agents Code approval UI. +Headless `dcode -n` is an explicit automation boundary with no approval UI. + +The managed headless path automatically approves non-shell tool requests such as file writes and edits, while still disabling shell execution, startup commands, interpreter tool calling, executable hooks, unmanaged MCP files, nested remote sandboxes, remote async subagents, and alternate model routes. + +| Aspect | Detail | +|---|---| +| Default | Interactive `dcode` prompts for destructive tools. Headless `dcode -n` auto-approves non-shell tools and keeps shell execution disabled. | +| What you can change | Choose interactive `dcode` when you need to review tool calls. Use `dcode -n` only for tasks where unattended file edits are acceptable. The interactive `thread-opt-in` capability does not change this headless boundary. | +| Risk if relaxed | Treating headless mode like an interactive approval session can let file edits happen without a human prompt. | +| Recommendation | Use the interactive TUI for sensitive repositories or destructive tasks. Reserve `dcode -n` for bounded automation with a reviewed workspace and policy. | + + + +## Non-Root User + +The sandbox runs agent processes as a dedicated `sandbox` user and group. +The entrypoint starts as root for privilege separation, then drops to the `sandbox` user for all agent commands. + +| Aspect | Detail | +|---|---| +| Default | `run_as_user: sandbox`, `run_as_group: sandbox`. A separate `gateway` user runs the gateway process. | +| What you can change | Change the `process` section in the policy file to run as a different user. | +| Risk if relaxed | Running as `root` inside the container gives the agent access to modify any file in the container filesystem and increases the impact of container escape vulnerabilities. | +| Recommendation | Never run as root. Keep the `sandbox` user. | + +## PATH Hardening + +The entrypoint locks the `PATH` environment variable to system directories, preventing the agent from injecting malicious binaries into command resolution. + +| Aspect | Detail | +|---|---| +| Default | The default sandbox entrypoint sets `PATH` to `/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin` at startup. Agent-specific images may add locked read-only runtime directories, such as `/opt/venv/bin` for LangChain Deep Agents Code. | +| What you can change | This is not a user-facing knob. The entrypoint enforces it. | +| Risk if relaxed | Without PATH hardening, the agent could create an executable named `curl` or `git` in a writable directory earlier in the PATH, intercepting commands run by the entrypoint or other processes. | +| Recommendation | No action needed. The entrypoint handles this automatically. | + +## Build Toolchain Removal + +The Dockerfile removes compilers and network probes from the runtime image. + +| Aspect | Detail | +|---|---| +| Default | The Dockerfile purges `gcc`, `gcc-12`, `g++`, `g++-12`, `cpp`, `cpp-12`, `make`, `netcat-openbsd`, `netcat-traditional`, and `ncat` from the sandbox image. | +| What you can change | Modify the Dockerfile to keep these tools, or install them at runtime if package manager access is allowed. | +| Risk if relaxed | A compiler lets the agent build arbitrary native code, including kernel exploits or custom network tools. `netcat` enables arbitrary TCP connections that bypass HTTP-level policy enforcement. | +| Recommendation | Keep build tools removed. If the agent needs to compile code, run the build in a separate, purpose-built container and copy artifacts into the sandbox. | + +## Image Digest Pinning + +The blueprint references the sandbox image by an immutable `@sha256:` digest instead of a mutable tag such as `:latest`. +A registry compromise or accidental force-push cannot silently swap the sandbox image. + +| Aspect | Detail | +|---|---| +| Default | `nemoclaw-blueprint/blueprint.yaml` pins the sandbox image by digest. A CI regression test blocks any mutable-tag reference from merging. | +| What you can change | Contributors bumping the sandbox image must update the digest in `blueprint.yaml`. Release tooling should rewrite the digest automatically. | +| Risk if relaxed | Reverting to a mutable tag (`:latest`) allows a registry-side change to replace the sandbox image without any blueprint update, which is a supply-chain risk. | +| Recommendation | Always reference the sandbox image by digest. If you build a custom image with the onboarding `--from` path, the digest constraint does not apply to your local build. | + + + +## Auth Profile Permissions + +The entrypoint and migration flows enforce `chmod 600` on all `auth-profiles.json` files under `~/.openclaw`. +This prevents other users on the host from reading stored credentials. + +| Aspect | Detail | +|---|---| +| Default | `600` permissions applied recursively at startup and after migration restores. | +| What you can change | This is not a user-facing knob. The entrypoint enforces it. | +| Risk if relaxed | Looser permissions let other users or processes on the host read provider API keys and tokens stored in auth profiles. | +| Recommendation | No action needed. If you see a `permission denied` error when reading auth profiles, verify that you are running as the same user who created them. | + +