Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Security: nanocoai/nanoclaw

Security

docs/SECURITY.md

NanoClaw Security Model

Trust Model

Entity Trust Level Rationale
Main group Trusted Private self-chat, admin control
Non-main groups Untrusted Other users may be malicious
Container agents Sandboxed Isolated execution environment
Incoming messages User input Potential prompt injection

Security Boundaries

1. Container Isolation (Primary Boundary)

Agents execute in containers (lightweight Linux VMs), providing:

  • Process isolation - Container processes cannot affect the host
  • Filesystem isolation - Only explicitly mounted directories are visible
  • Non-root execution - Runs as unprivileged node user (uid 1000)
  • Ephemeral containers - Fresh environment per invocation (--rm)

This is the primary security boundary. Rather than relying on application-level permission checks, the attack surface is limited by what's mounted.

2. Mount Security

External Allowlist - Mount permissions stored at ~/.config/nanoclaw/mount-allowlist.json, which is:

  • Outside project root
  • Never mounted into containers
  • Cannot be modified by agents

Default Blocked Patterns:

.ssh, .gnupg, .aws, .azure, .gcloud, .kube, .docker,
credentials, .env, .netrc, .npmrc, id_rsa, id_ed25519,
private_key, .secret

Protections:

  • Symlink resolution before validation (prevents traversal attacks)
  • Container path validation (rejects .. and absolute paths)
  • nonMainReadOnly option forces read-only for non-main groups

Read-Only Project Root:

The main group's project root is mounted read-only. Writable paths the agent needs (store, group folder, IPC, .claude/) are mounted separately. This prevents the agent from modifying host application code (src/, dist/, package.json, etc.) which would bypass the sandbox entirely on next restart. The store/ directory is mounted read-write so the main agent can access the SQLite database directly.

3. Session Isolation

Each group has isolated Claude sessions at data/sessions/{group}/.claude/:

  • Groups cannot see other groups' conversation history
  • Session data includes full message history and file contents read
  • Prevents cross-group information disclosure

4. IPC Authorization

Messages and task operations are verified against group identity:

Operation Main Group Non-Main Group
Send message to own chat
Send message to other chats
Schedule task for self
Schedule task for others
View all tasks Own only
Manage other groups

5. Credential Isolation (OneCLI Agent Vault)

Real API credentials never enter containers. NanoClaw uses OneCLI's Agent Vault to proxy outbound requests and inject credentials at the gateway level.

How it works:

  1. Credentials are registered once with onecli secrets create, stored and managed by OneCLI
  2. When NanoClaw spawns a container, it calls applyContainerConfig() to route outbound HTTPS through the OneCLI gateway
  3. The gateway matches requests by host and path, injects the real credential, and forwards
  4. Agents cannot discover real credentials — not in environment, stdin, files, or /proc

Per-agent policies: Each NanoClaw group gets its own OneCLI agent identity. This allows different credential policies per group (e.g. your sales agent vs. support agent). OneCLI supports rate limits, and time-bound access and approval flows are on the roadmap.

NOT Mounted:

  • Channel auth sessions (store/auth/) — host only
  • Mount allowlist — external, never mounted
  • Any credentials matching blocked patterns
  • .env is shadowed with /dev/null in the project root mount

6. Egress Lockdown (Forced Proxy)

The HTTPS_PROXY env var only redirects proxy-aware clients — a tool that ignores it (or a raw socket) could reach the internet directly and bypass credential injection, approvals, and audit. Egress lockdown closes that hole at the network layer.

How it works: agents are placed on a Docker --internal network (nanoclaw-egress) that has no route to the internet. The OneCLI gateway container is attached to that network, aliased as host.docker.internal, so the injected proxy URL (...@host.docker.internal:10255) resolves to the gateway container-to-container. The gateway is therefore the only reachable hop — anything else has nowhere to go. The agent is non-root with no NET_ADMIN, so it cannot undo this. Identical mechanism on macOS and Linux (no host firewall, no host-gateway route).

  • Self-healing: the gateway is re-attached to the network at every spawn and on each host-sweep tick, so an out-of-band detach (e.g. docker compose up on the OneCLI stack — its compose lives in ~/.onecli, not this repo) recovers automatically.
  • Fail-fast: if lockdown is on but the network can't be created or the gateway can't be attached (e.g. a non-standard gateway container name, or the gateway isn't running), nanoclaw refuses to spawn the agent and surfaces a clear error — it never silently falls back to open egress. Fix the cause (or set NANOCLAW_EGRESS_LOCKDOWN=false) and retry. The host-sweep re-heal is the exception: a heal failure there is logged but not fatal, since already-running agents stay on the internal net (no leak) until the gateway returns.

Configuration:

Env Default Meaning
NANOCLAW_EGRESS_LOCKDOWN false Set true to opt in (otherwise the host-gateway path is used). Enabled automatically by /add-golden-registry.
NANOCLAW_EGRESS_NETWORK nanoclaw-egress Network name.
ONECLI_GATEWAY_CONTAINER onecli Gateway container to attach.

⚠ Behavior when enabled: with lockdown on, agents have no direct internet — all traffic must go through OneCLI. Proxy-aware clients (npm, pnpm, pip, curl, node/bun with the proxy env) are unaffected. Any workflow that relies on a non-proxy-aware tool reaching the internet directly will fail by design. Lockdown is off by default; opt in with NANOCLAW_EGRESS_LOCKDOWN=true.

Privilege Comparison

Capability Main Group Non-Main Group
Project root access /workspace/project (ro) None
Store (SQLite DB) /workspace/project/store (rw) None
Group folder /workspace/group (rw) /workspace/group (rw)
Global memory Implicit via project /workspace/global (ro)
Additional mounts Configurable Read-only unless allowed
Network access Unrestricted Unrestricted
MCP tools All All

Security Architecture Diagram

┌──────────────────────────────────────────────────────────────────┐
│ UNTRUSTED ZONE │
│ Incoming Messages (potentially malicious) │
└────────────────────────────────┬─────────────────────────────────┘
 │
 ▼ Trigger check, input escaping
┌──────────────────────────────────────────────────────────────────┐
│ HOST PROCESS (TRUSTED) │
│ • Message routing │
│ • IPC authorization │
│ • Mount validation (external allowlist) │
│ • Container lifecycle │
│ • OneCLI Agent Vault (injects credentials, enforces policies) │
└────────────────────────────────┬─────────────────────────────────┘
 │
 ▼ Explicit mounts only, no secrets
┌──────────────────────────────────────────────────────────────────┐
│ CONTAINER (ISOLATED/SANDBOXED) │
│ • Agent execution │
│ • Bash commands (sandboxed) │
│ • File operations (limited to mounts) │
│ • API calls routed through OneCLI Agent Vault │
│ • No real credentials in environment or filesystem │
└──────────────────────────────────────────────────────────────────┘

Supply Chain Security (pnpm)

NanoClaw uses pnpm with two supply chain defenses configured in pnpm-workspace.yaml:

Minimum Release Age

minimumReleaseAge: 4320 (3 days). pnpm will refuse to resolve any package version published less than 3 days ago. This defends against typosquatting and compromised maintainer accounts — most malicious publishes are detected and pulled within 72 hours.

Excluding a package from the release age gate (minimumReleaseAgeExclude):

This should be rare. When a zero-day fix or critical dependency requires an immediate update:

  1. The exclusion must be reviewed and approved by a human maintainer
  2. The entry must pin the exact version being excluded — never a range or wildcard
    minimumReleaseAgeExclude:
     some-package: "1.2.3" # Approved by @user, 2026年04月14日 — CVE-XXXX-YYYY fix
  3. The exclusion should be removed once the version ages past the threshold (i.e. after 3 days)
  4. Automated agents (Claude, CI bots) must never add exclusions without human sign-off

Build Script Allowlist

onlyBuiltDependencies restricts which packages can execute install/postinstall scripts. Only packages on this list are permitted to run build scripts during pnpm install. Currently allowed:

  • better-sqlite3 — compiles native SQLite bindings
  • esbuild — downloads platform-specific binary
  • protobufjs — generates protobuf bindings (used by Baileys/libsignal)
  • sharp — downloads platform-specific image processing binary

Adding a package to this list requires human approval — build scripts execute arbitrary code with the installing user's permissions.

.npmrc Safety Net

The .npmrc file contains minReleaseAge=3d as a fallback. The authoritative setting is in pnpm-workspace.yaml, but .npmrc provides defense-in-depth if npm is ever invoked directly (e.g. by a tool that doesn't respect pnpm).

There aren't any published security advisories

AltStyle によって変換されたページ (->オリジナル) /