Skip to content

Security Model

Netclaw is default-deny. Every tool call, file access, and shell command starts blocked and must be explicitly permitted. Any policy failure — invalid config, engine exception, unrecognized channel — results in deny.

Audiences control what’s allowed. A four-layer invocation stack enforces it. You pick a deployment posture during netclaw init, and it governs every permission decision the daemon makes.

Netclaw classifies each inbound message into one of three audiences based on the channel it arrived on:

ChannelAudience
TUI (netclaw chat), SignalR (real-time web transport), headless (no UI, daemon-only), console, manualPersonal
Slack, Discord, reminders, timersTeam
Unknown channel typePublic

Personal is the most permissive, Public the most restrictive. Unknown channels resolve to Public. If netclaw can’t identify who’s talking, it assumes the worst.

During netclaw init, you pick a deployment posture that sets the baseline trust level:

Security posture selection during netclaw init

The posture selection screen during netclaw init. Personal mode enables shell access with approval gates; Team and Public disable shell entirely.

PostureShell AccessDefault Behavior
PersonalEnabled (with approval gates)All tools available, all MCP servers, unrestricted filesystem
TeamOffAllowlisted tools only, no MCP servers, session-scoped filesystem (temp directory per session, wiped on end)
PublicOffMinimal tool set, no MCP servers, session-scoped filesystem (temp directory per session, wiped on end)

With no config file at all, netclaw defaults to Public posture with shell disabled — the most restrictive option.

Posture and audience are related but distinct. Posture is a deployment-wide setting you choose once. Audience is resolved per-message based on channel. A Team-posture deployment still classifies TUI sessions as Personal audience.

Tools, filesystem access, and attachment policies differ by audience:

AudienceToolsMCP ServersFilesystemAttachment Types
PersonalAllAllUnrestrictedImage, PDF, Document, Archive, Media, Other
Teamfile_read, attach_fileNoneSession-scoped onlyImage, PDF, Document, Archive, Media
Publicfile_read, file_write, attach_fileNoneSession-scoped onlyImages only

Public having file_write while Team doesn’t looks backwards — Public’s file_write is restricted to the session-scoped temp directory (which is wiped on session end), so the blast radius is minimal. Team omits it because Team sessions are longer-lived and shared across users.

MCP server permissions are managed separately per audience through netclaw mcp permissions. New MCP servers start with zero tool grants for all audiences — you must explicitly enable them.

Tool calls pass through four layers in sequence. If any layer rejects, execution stops.

┌─────────────────────────────────┐
│ 1. Operation Hard Deny │ ← blocks dangerous commands
├─────────────────────────────────┤
│ 2. Resource Hard Deny │ ← blocks protected file paths
├─────────────────────────────────┤
│ 3. Tool Access Grant │ ← audience-based allowlist
├─────────────────────────────────┤
│ 4. Approval Gate │ ← human confirms execution
└─────────────────────────────────┘

Shell commands hit a hard-deny list first. Blocked regardless of audience or approval status:

CategoryBlocked
Self-destructivenetclaw daemon stop, netclaw daemon kill, systemctl stop netclaw, systemctl kill netclaw, kill, killall, pkill
Privilege escalationsudo, su, doas
System destructionrm -rf /, rm -rf ~/, mkfs*
Fork bombs:(){ :|:& };:, :(){:|:&};:

Add your own patterns in ~/.netclaw/config/netclaw.json:

{
"Tools": {
"HardDenyPatterns": ["docker rm", "kubectl delete namespace"]
}
}

File access is checked against protected paths. Read and write have separate deny lists:

OperationDenied paths
Read~/.netclaw/config/secrets.json, ~/.netclaw/keys/, ~/.netclaw/config/webhooks/
Write~/.netclaw/config/secrets.json, ~/.netclaw/keys/, SQLite DB, PID file, lock file, restart manifest

~/.netclaw/config/netclaw.json is intentionally not denied — the agent can read (but not write) the main config file.

Netclaw resolves symlinks before checking, so ln -s ~/.netclaw/keys/ ./sneaky won’t bypass the policy.

The audience profile determines which tools exist at all. Public and Team audiences only see allowlisted tools (see the per-audience table). Ungranted tools are invisible to the model — they don’t appear in the tool list at all.

MCP tool grants are configured separately per server and per audience through netclaw mcp permissions.

Tools that pass layers 1-3 hit the approval gate, which prompts the operator for confirmation:

OptionBehavior
Approve onceValid for the current session only
Approve alwaysPersisted to ~/.netclaw/config/tool-approvals.json (edit this file directly to revoke)
DenyBlocks this invocation

Approval timeouts work differently depending on the channel:

  • Interactive channels (TUI, Slack, Discord, SignalR) — no response within 5 minutes triggers auto-deny. The LLM gets an error message but has no idea an approval gate rejected it.
  • Non-interactive channels (headless, reminders, webhooks) — approval gates are structurally unsupported, so all gated tools are auto-denied immediately.

Compound commands (cmd1 && cmd2 | cmd3) are split into segments, each checked independently. Unapproved patterns are batched into a single prompt.

ChannelApproval Support
TUI, Slack, Discord, SignalRYes
Headless, reminders, webhooksNo — auto-deny

The redactor strips secrets from command stdout before the model sees them. It catches:

  • API key prefixes: sk-*, Slack API tokens (xox[baprs]-...), ghp_*, AKIA*
  • Authorization: Bearer headers
  • JSON fields matching sensitive names: api_key, api-key, apikey, token, secret, password, authorization, access_token, refresh_token, client_secret, signing_key, private_key, connection_string, credential
  • Connection strings with Password= or Pwd=
  • JWT tokens and PEM private key blocks

For encryption at rest, see netclaw secrets.

Netclaw scans inbound content — tool output, file contents, MCP server responses — for injection patterns. Detection returns a risk level per match; callers (the invocation stack layers) decide whether to reject or warn.

CategoryExamplesRisk Level
Prompt injection”ignore previous instructions”High
Role resetsYouAreNow-style patternsMedium
Data exfiltration”exfiltrate secrets via curl”High
Privilege escalationAccess control list (ACL) modification, admin grantsHigh
Destructive operationsrm -rf, DROP TABLEHigh
Invisible unicodeZero-width chars, BiDi control charactersMedium
Private Use Area charsPUA codepointsLow

High-risk matches are rejected outright. Medium-risk matches generate warnings. Low-risk matches are allowed through.

Before accepting a file upload, netclaw validates:

  • MIME type must be on the audience’s allowlist
  • Maximum file size: 25 MiB
  • File headers are checked against declared MIME types (magic byte validation) — renaming malware.exe to photo.png won’t work

Exposure mode controls network reachability. It’s separate from audience and posture:

ModeScopeRequires
localLoopback onlyNothing (default)
tailscale-serveYour tailnettailscaled
tailscale-funnelPublic internettailscaled
cloudflare-tunnelPublic internetcloudflared

Internet-reachable modes force explicit confirmation during netclaw init and trigger high-risk diagnostic warnings. Changing exposure mode requires a daemon restart — not hot-reloaded.

A Personal-posture deployment exposed via Tailscale Funnel is reachable from the internet but still applies Personal audience rules to TUI sessions and Team rules to Slack. Exposure and audience are orthogonal.

When in doubt, netclaw denies:

  • Invalid ACL schema in config → daemon refuses to start
  • Policy engine throws an exception → deny
  • Unknown channel type → Public audience (most restrictive)
  • No config file → Public posture, shell off
  • Approval gate timeout → auto-deny
  • MCP server with no tool grants → all tools blocked

There is no permissive mode — access must be explicitly granted.

  • Prompt injection detection uses regex pattern matching, not semantic analysis — novel phrasings can evade it
  • Approval gates require an interactive channel — headless, reminder, and webhook sessions auto-deny all gated tools
  • Secret redaction catches known patterns only — custom secret formats need custom hard-deny path rules
  • Content validation checks magic bytes but doesn’t deep-scan file contents for embedded threats
  • Per-channel audience overrides exist (ChannelAudiences config) but require manual channel ID mapping — there’s no UI for it yet
  • netclaw init — posture selection and network exposure configuration
  • netclaw secrets — encrypted credential storage and output redaction
  • netclaw mcp — per-audience MCP tool permissions
  • netclaw webhooks — HMAC verification and audience assignment for inbound webhooks
  • Hardening — additional lockdown recommendations for production deployments