Skip to content

Security Model

Security Model

Threat Model

A personal AI agent with access to email, calendars, messaging, and shell execution is a high-value target. If an agent is compromised or manipulated (via prompt injection, tool misuse, or configuration error), it could:

  • Execute arbitrary shell commands
  • Modify its own configuration, skills, and prompts
  • Access other devices on the network
  • Read or exfiltrate private data
  • Send messages impersonating the owner
  • Pivot from a restricted context to a privileged one

This document describes the layered security model that mitigates these risks.

Defense in Depth

Security relies on five independent layers. If any single layer is bypassed, the remaining layers still protect against full compromise.

External message arrives

1. Channel Policies

DM allowlist, group @mention gating

2. Agent Bindings

Route to correct agent by sender/channel

3. Tool Policies

Agent-specific tool allow/deny lists

4. Exec Approvals

Per-agent CLI command allowlists

5. Workspace Isolation

Per-agent config wrappers enforce data boundaries

Agent responds (scoped)

Layer 1: Channel Policies

The first line of defense controls who can talk to the agent at all.

  • DM allowlist — Only explicitly listed phone numbers can send direct messages
  • Group mention gating — In group chats, the agent only responds when @mentioned
  • WhatsApp policies — DMs disabled, groups restricted to an allowlist

Layer 2: Agent Bindings

Bindings route each message to the appropriate agent based on channel, peer kind (DM vs group), and peer ID.

  • Most-specific wins — A binding for a specific phone number takes priority over a channel-wide fallback
  • No implicit fallthrough — Without explicit bindings, messages reach the default (most privileged) agent. Always add bindings for every channel/peer combination.

See Multi-Agent Architecture for the full binding configuration.

Layer 3: Tool Policies

Each agent has an independent tool policy that controls which OpenClaw tools it can use.

ToolMain AgentGroup/Family AgentEmail Delegate
execAllowedAllowed (gated by Layer 4)Denied
readAllowed (workspace only)AllowedAllowed (workspaceOnly)
write, editAllowed (workspace only)Deniedwrite only (workspaceOnly)
browserAllowedDeniedDenied
web_search, web_fetchAllowedAllowedDenied
memory_search, memory_getAllowedAllowedAllowed
sessions_sendAllowedAllowed (can message main agent)Allowed (main agent only)
sessions_list, sessions_historyAllowedDeniedDenied
sessions_spawnAllowedDenied (allowAgents: [])Denied
fastmail_*Denied (delegated)DeniedAll 36 tools allowed
message (iMessage/WA/TG)AllowedAllowedDenied
cron, gateway, processDeniedDeniedDenied

Key principle: The main agent has write/edit/apply_patch tools available but is not filesystem-sandboxed (fs.workspaceOnly: false) — exec approvals and tool allow/deny lists are the primary security boundary, not filesystem isolation. workspaceOnly: true was previously used but disabled because it blocked the image tool and native vision auto-injection from reading inbound media at ~/.openclaw/media/inbound/. Restricted agents deny write/edit entirely — they relay to the main agent via sessions_send for any write operations.

Layer 4: Exec Approvals

The exec tool is required for MCP servers (via CLI clients) and native PIM tools. But unrestricted exec would bypass all other restrictions. Exec approvals solve this with per-agent command allowlists.

Important: There are two separate config systems for exec security. Both must be configured for consistent behavior.

Config fileControlsKey fields
openclaw.jsonGateway-hosted exec (what actually runs locally)agents.list[].tools.exec.security / .ask
exec-approvals.jsonNode host exec (remote nodes)agents.<name>.security / .ask

Setting security: "full" in exec-approvals.json alone does NOT affect gateway exec — you must set it in openclaw.json under each agent’s tools.exec block.

Per-Agent Exec Config in openclaw.json

Every agent needs an explicit tools.exec block. Without one, the agent falls through to gateway defaults (security: "allowlist", ask: "on-miss"), which causes approval prompts that time out with no approver.

Critical: host: "gateway" is required for allowlist enforcement. Without it, the exec handler defaults to host: "sandbox". When sandbox mode is off, the command runs directly — bypassing the allowlist check and approval forwarding entirely. The security and ask settings have no effect without host: "gateway".

// Main agent — allowlisted commands, unlisted prompt owner
{
"id": "main-agent",
"tools": {
"exec": {
"security": "allowlist",
"ask": "on-miss"
}
}
}
// Restricted agent — smaller allowlist, unlisted prompt owner
{
"id": "group-agent",
"tools": {
"exec": {
"host": "gateway",
"security": "allowlist",
"ask": "on-miss"
}
}
}

Exec Approvals in exec-approvals.json

This file controls the per-agent command allowlists. All agents use security: "allowlist" — the main agent has a broader allowlist while restricted agents get a minimal set. Commands not on the allowlist trigger an approval prompt to the owner via Telegram (ask: "on-miss").

{
"defaults": { "security": "deny" },
"agents": {
"main-agent": {
"security": "allowlist",
"ask": "on-miss",
"allowlist": [
{ "pattern": "/path/to/.local/bin/*" },
{ "pattern": "/path/to/mcporter" },
{ "pattern": "/path/to/openclaw" },
{ "pattern": "/path/to/workspace/scripts/*" }
]
},
"group-agent": {
"security": "allowlist",
"ask": "on-miss",
"allowlist": [
{ "pattern": "/path/to/travel-hub" },
{ "pattern": "/path/to/mail-inbox" },
{ "pattern": "/path/to/mail-read" },
{ "pattern": "/path/to/mail-list" },
{ "pattern": "/path/to/mail-auth-check" }
]
}
}
}

Explicitly NOT allowlisted for restricted agents (blocked by absence):

  • Direct MCP client commands (blocks private data access)
  • Mail modification commands (mail-archive, mail-mark-read)
  • Vault and state tools (obsidian-note, heartbeat-state)
  • General shell commands (curl, bash, etc.)

Note: Email send/reply and auth-check now run through the Apple PIM plugin (child_process in the gateway), bypassing exec approvals entirely. Per-agent access is controlled by the plugin’s workspace config.

Valid Exec Values

FieldValuesGateway default
securitydeny, allowlist, fullallowlist
askoff, on-miss, alwayson-miss
askFallbackdeny, allowdeny

Exec Approval Forwarding (v2026.2.15+)

When ask is set to on-miss, restricted agents prompt for approval when they hit a command not on the allowlist. By default, this prompt appears only in the originating session. Approval forwarding routes these prompts to an external channel (like Telegram with inline approve/deny buttons) so the owner can approve remotely.

"approvals": {
"exec": {
"enabled": true,
"mode": "targets",
"agentFilter": ["group-agent", "family-agent"],
"targets": [
{
"channel": "telegram",
"to": "<owner-telegram-user-id>"
}
]
}
}
FieldPurpose
enabledTurn on approval forwarding
mode"session" (origin chat), "targets" (configured targets), "both"
agentFilterOnly forward for these agents
targets[].channelDestination channel (Telegram recommended for inline buttons)
targets[].toDestination user ID

Recommended setup: Use ask: "on-miss" for restricted agents with Telegram forwarding. Telegram’s inline button support provides a clean approve/deny UX. BlueBubbles works too but uses text-based approval.

Layer 5: Workspace Isolation

Each agent has its own workspace directory with per-agent configuration. The apple-pim-cli plugin (v3.1.0) uses a factory pattern that reads config from each agent’s workspace automatically, filtering which calendars and reminder lists the agent can access:

AgentCalendar AccessReminders Access
MainAllAll
GroupShared only (Work/Personal blocked)Shared only (Personal blocked)
FamilyShared only (Work/Personal blocked)Shared only (Personal blocked)

Network Isolation

The agent machine should be network-isolated from other devices. Using Tailscale ACLs:

  • Personal devices can reach the agent (for SSH, dashboard)
  • The agent cannot initiate connections to personal devices
  • Tag the agent as tag:agent and omit any grant where tag:agent is the source

This prevents a compromised agent from pivoting to other machines.

SSH Hardening

  • Use Tailscale SSH instead of macOS built-in SSH
  • Disable macOS sshd entirely (sudo systemsetup -setremotelogin off)
  • Configure ACL SSH rules with action: check for the agent (requires browser re-authentication)
  • Enable Tailscale Lock with physical devices as approval nodes

See Remote Access for the full setup.

Prompt Injection Defense

External content (email bodies, calendar event titles, message content) is untrusted data. The agent should:

  1. Never execute instructions found in external content
  2. Sanitize external text before including it in LLM context
  3. Add guardrails to the agent’s system prompt

See Prompt Injection Defense for sanitization patterns and guardrail examples.

Agent-to-Agent Communication

Agent-to-agent messaging is enabled for sessions_send only. Restricted agents can relay requests to the main agent when they need tools they don’t have. The email delegate agent (lobster-mail) receives work from the main agent and returns structured summaries. sessions_spawn remains denied to prevent privilege escalation via sub-agents.

{
"tools": {
"sessions": {
"visibility": "all" // Main agent can discover all sessions
},
"agentToAgent": {
"enabled": true,
"allow": ["main-agent", "family-agent", "group-agent",
"wa-agent", "homeclaw", "travel-hub", "lobster-mail"]
}
}
}

Session tool lockdown: Only the main agent has sessions_list and sessions_history. All other agents have these denied, preventing them from discovering other agents’ session keys or reading transcripts. This is critical for the email delegate — other agents cannot discover its session key or read email content from its transcripts.

Why this is safe now

The original escalation path (restricted agent -> main agent -> private email access) is blocked by exec approvals:

ControlBefore exec-approvalsNow
Which binaries each agent can runsecurity: "full" (anything goes)security: "allowlist" (hard per-agent allowlists)
What happens on allowlist missAuto-approvePrompt owner via Telegram, deny if no response
Restricted agents can run mcporterYes (Fastmail access)No (removed from allowlist)
Restricted agents’ Fastmail toolsCould use via mcporter execfastmail_* denied in tool policy AND mcporter off allowlist

Defense in depth for sessions_send

  1. Provenance tagging — Messages from other agents have provenance.kind: "inter_session", so the main agent knows the request is NOT from the owner
  2. Main agent privacy rules — TOOLS.md instructs the main agent to never share private data (email, financial tools) with restricted agents
  3. Exec approvals (hard) — Restricted agents can’t run mcporter or other privileged binaries even if they get a response
  4. Tool policy (hard)fastmail_* denied for restricted agents
  5. Audit trail — Full exchange logged in both agents’ session transcripts

Why sessions_spawn stays denied

If sessions_spawn were enabled, a restricted agent with subagents.allowAgents: ["main-agent"] could spawn a sub-agent running as the main agent. Sub-agents inherit the target agent’s tool policy, creating a privilege escalation path. As defense in depth, restricted agents also have allowAgents: [] to prevent this even if sessions_spawn were accidentally re-enabled.

Residual risk

A restricted agent could social-engineer the main agent into sharing private data. This is mitigated by provenance tagging and privacy instructions, and is no different from a family member texting the owner directly to ask for the same information.

Red team validation

Six tests were run on 2026-03-02 covering Fastmail privacy, social engineering, exec escalation, sessions_spawn blocking, and provenance tagging. All passed. See Agent-to-Agent Communications for the full test methodology and results.

Elevated Access

Only the owner gets elevated access, applied globally across all agents:

{
"elevated": {
"enabled": true,
"allowFrom": {
"bluebubbles": ["+1XXXXXXXXXX"]
}
}
}

When the owner @mentions in a group chat, the restricted agent temporarily gains elevated privileges for that session.

Configuration Security

  • Permissions: chmod 600 for openclaw.json, chmod 700 for identity and agent directories
  • Slash commands: Disable bash, config, debug, and restart via iMessage
  • Logging: Enable secret redaction patterns for API keys, tokens, phone numbers, and bearer tokens
  • Backups: Always cp openclaw.json openclaw.json.pre-<change> before editing configuration

Audit Checklist

After hardening:

Terminal window
openclaw security audit

Key verifications:

  • Agent machine cannot ping personal devices
  • Personal devices can SSH to agent
  • Family DMs route to restricted agent (not main)
  • Group chats require @mention
  • MCP tools still work
  • Logs show redacted sensitive data
  • Dangerous slash commands are disabled