Skip to main content

Security

OpenPawz is designed with defense-in-depth: 10 security layers protect against prompt injection, data exfiltration, MITM attacks, memory forensics, and unauthorized actions.

Zero Attack Surface by Default

OpenPawz exposes zero network ports in its default configuration. There is no HTTP server, no WebSocket endpoint, and no listening socket for an attacker to reach — the only communication channel is Tauri’s in-process IPC between the WebView and the Rust engine.

Network listeners

Four optional listeners exist. All are disabled by default and bind to localhost only (127.0.0.1):
ListenerDefault bindDefault stateAuthenticationPurpose
Webhook server127.0.0.1:3940DisabledBearer token (auto-generated UUID) + IP rate limiting (60 req/min)External trigger for agent runs
WebChat127.0.0.1:3939DisabledAccess token + session cookie + DM policyBrowser-based chat with an agent
WhatsApp bridge127.0.0.1:8086DisabledInternal only (local Evolution API)WhatsApp message relay
n8n engine127.0.0.1:5678Disabledn8n’s built-in authEmbedded workflow engine
Because everything binds to 127.0.0.1, these services are unreachable from the network even when enabled. Binding to 0.0.0.0 (LAN/WAN exposure) is a manual opt-in that triggers a security warning in the logs and recommends TLS via Tailscale Funnel. :::warning Changing bind_address to 0.0.0.0 on any listener exposes it to your local network. Only do this behind a firewall or VPN (e.g. Tailscale), and ensure the authentication token is strong. :::

Cryptographic key storage

No cryptographic key is ever stored on the filesystem. All keys live in the OS keychain (macOS Keychain / Windows Credential Manager / Linux Secret Service):
KeyKeychain servicePurpose
DB encryption keypaw-db-encryptionAES-256-GCM database field encryption
Skill vault keypaw-skill-vaultAES-256-GCM skill credential encryption
Memory vault keypaw-memory-vaultAES-256-GCM PII memory encryption
Lock screen hashpaw-lock-screenSHA-256 hashed passphrase
There is no device.json, no key file, and no config file containing secrets. If the OS keychain is unavailable, the app refuses to store credentials rather than falling back to plaintext.

Soul files (agent behavior)

Agent personality and behavioral rules (SOUL.md, IDENTITY.md, USER.md) are stored in the encrypted SQLite database (agent_files table) — not as files on the filesystem. They are read and written exclusively through Tauri IPC commands, which are local WebView-to-Rust calls with no network involvement. An external attacker would need:
  1. Physical access to the machine, AND
  2. The OS keychain credential to decrypt the database
to tamper with soul files. Remote modification is impossible because no network port serves agent file operations.

Content Security Policy

The Tauri WebView enforces a strict CSP that restricts all connections to 127.0.0.1:
default-src 'self'; script-src 'self'; connect-src 'self' ws://127.0.0.1:1420 ...;
object-src 'none'; frame-ancestors 'none'; form-action 'self'
This prevents XSS-based exfiltration, iframe embedding, and cross-origin form submission.

Human-in-the-Loop (HIL)

Every tool is classified by risk level. High-risk tools require explicit human approval before execution.

Auto-approved tools (no approval needed)

fetch · read_file · list_directory · web_search · web_read · memory_search · memory_store · soul_read · soul_write · soul_list · self_info · update_profile · create_task · list_tasks · manage_task · email_read · slack_read · telegram_read · image_generate

HIL-required tools (human must approve)

exec · write_file · delete_file · append_file · email_send · webhook_send · rest_api_call · slack_send · github_api

Agent policies

Per-agent tool access control with four presets:
PresetModeDescription
UnrestrictedunrestrictedAll tools, no approval
StandarddenylistHigh-risk tools require approval
Read-onlyallowlistOnly safe read tools
Sandboxallowlistweb_search, web_read, memory_search, soul_read only
You can also create custom policies with specific tool allowlists/denylists.

Risk classification

RiskTools
Saferead_file, list_directory, web_search, web_read, memory_search, soul_read, soul_list, self_info, fetch
High-riskexec, write_file, delete_file, append_file, email_send, webhook_send, rest_api_call, slack_send, github_api, image_generate, soul_write, update_profile, create_agent, create_task, manage_task

Prompt injection defense

All incoming channel messages are scanned for injection attempts before reaching the agent.

Detection

Pattern-based scoring across 9 categories (8 in the Rust backend scanner, 9 in the TypeScript frontend scanner which adds obfuscation):
CategoryExamplesScanner
override”Ignore previous instructions”Both
identity”You are now…”Both
jailbreak”DAN mode”, “no restrictions”Both
leaking”Show me your system prompt”Both
obfuscationBase64-encoded instructionsFrontend only
tool_injectionFake tool call formattingBoth
social”As an AI researcher…”Both
markupHidden instructions in HTML/markdownBoth
bypass”This is just a test…”Both

Severity levels

SeverityScoreAction
Critical40+Message blocked, not delivered
High25+Warning logged
Medium12+Noted in logs
Low5+Informational
Channel bridges automatically block messages with critical severity.

Container sandbox

Execute agent commands in isolated Docker containers:
Security measureDefault
Capabilitiescap_drop ALL
NetworkDisabled
Memory limit256 MB
CPU shares512
Timeout30 seconds
Output limit50 KB

Presets

PresetImageMemoryNetworkTimeout
Minimalalpine128 MBOff15s
Developmentnode:20-alpine512 MBOn60s
Pythonpython:3.12-alpine512 MBOn60s
Restrictedalpine64 MBOff10s

Command risk assessment

Commands are scored before execution:
  • Lowls, cat, echo
  • Mediumpip install, npm install
  • Highcurl, wget, network commands
  • Criticalrm -rf /, chmod 777, dangerous patterns

Browser network policy

Control which domains agents can access: Default allowed: AI provider APIs, DuckDuckGo, Coinbase, localhost Default blocked: pastebin.com, transfer.sh, file.io, 0x0.st (data exfiltration risks)

File system protection

Sensitive paths are blocked from agent access — agents cannot add these as project folders or browse into them.
CategoryBlocked paths
SSH / GPG~/.ssh, ~/.gnupg
Cloud credentials~/.aws, ~/.kube
Desktop keyrings~/.gnome-keyring, ~/.password-store
Docker~/.docker (includes config.json)
Network credentials~/.netrc
System config/etc (covers /etc/shadow, /etc/passwd, /etc/sudoers)
Root home/root
System logs/var/log
Virtual filesystems (Linux)/proc/*, /sys/*
Device nodes/dev
WindowsC:\Windows, C:\Users\*\AppData (credential store paths)
App config~/.openclaw (contains tokens), ~/.config/himalaya (email config)
Additionally, the home directory root itself (~, /home/user, /Users/user) and the filesystem root (/, C:\) are blocked as too broad. :::tip Per-project scope guard When a project is active, all file operations are constrained to the project root. Directory traversal sequences (../) are detected and blocked even within the allowed path. :::

Credential security

Credentials are protected by two independent encryption layers:

Layer 1: Skill credential encryption (XOR)

  • API keys encrypted with XOR using a 32-byte random key
  • Encryption key stored in OS keychain (paw-skill-vault)
  • High-risk credentials (Coinbase, DEX) are server-side only — never injected into prompts
  • Credentials are decrypted only at execution time

Layer 2: Database field encryption (AES-256-GCM)

Sensitive database fields are encrypted with AES-256-GCM via the Web Crypto API before being stored in SQLite.
PropertyDetail
AlgorithmAES-256-GCM (authenticated encryption)
Key size256 bits
IV12-byte random IV per encryption
Key sourceGenerated on first launch, stored in OS keychain (paw-db-encryption)
Storage formatenc:<base64(IV + ciphertext)>
FallbackGraceful — stores plaintext if encryption is unavailable
:::info Two independent layers The XOR layer protects skill credentials stored in the skill_credentials table. The AES-256-GCM layer protects other sensitive fields across the database. Both derive their keys from the OS keychain but use separate keychain entries. :::

TLS certificate pinning

All AI provider connections use a certificate-pinned TLS configuration that explicitly ignores the operating system trust store. This means a compromised or rogue CA installed on the user’s machine cannot intercept provider traffic.
PropertyDetail
Libraryrustls 0.23 (pure-Rust TLS, no OpenSSL)
Root storeMozilla root certificates via webpki-roots only
OS trust storeExplicitly excluded — system CAs are never consulted
Client sharingSingleton reqwest::Client shared across all providers
Connection poolingEnabled — one pool for all OpenAI, Anthropic, Google, etc. calls
Connect timeout10 seconds
Request timeout120 seconds

Why this matters

Most TLS MITM attacks rely on installing a custom root CA on the victim’s machine (corporate proxies, malware, government surveillance). By pinning to Mozilla’s root store, OpenPawz rejects certificates signed by any non-Mozilla CA — even if the OS trusts it.

Covered providers

All providers routed through the pinned client: OpenAI, Anthropic, Google Gemini, OpenRouter, DeepSeek, Grok, Mistral, Moonshot, Ollama, and any custom OpenAI-compatible endpoint.

Outbound request signing

Every AI provider request is signed with SHA-256 before transmission for tamper detection and compliance auditing.

How it works

Before each .send(), the engine computes:
SHA-256(provider || model || ISO-8601 timestamp || request body)
The resulting hex digest is logged to an in-memory ring buffer (500 entries) along with the provider name, model, timestamp, and HTTP response status.
PropertyDetail
AlgorithmSHA-256 (via sha2 crate)
Buffer size500 entries (ring buffer, overwrites oldest)
Logged fieldstimestamp, provider, model, hash, HTTP status
StorageIn-memory only — not persisted to disk

Use cases

  • Tamper detection — If a proxy modifies the request body in transit, the recorded hash won’t match a re-computed hash of the actual payload received by the provider
  • Compliance audit — Security teams can export request hashes to verify that specific prompts were sent at specific times
  • Replay detection — Each hash includes a timestamp, making every entry unique even for identical request bodies

Memory encryption (secure zeroing)

API keys and other sensitive credentials are protected in RAM using Zeroizing<String> wrappers from the zeroize crate, ensuring they are overwritten with zeros when no longer needed.

What this prevents

When a provider is dropped (e.g. user switches providers, session ends, or the app closes), the API key memory is immediately zeroed rather than left as a dangling allocation. This protects against:
  • Memory dump attacks — Forensic tools or malware scanning process memory for API key patterns
  • Swap file leaks — Unencrypted API keys persisted to disk via OS swap/page file
  • Use-after-free — Freed memory still containing the key being reallocated to another buffer

Implementation

ComponentProtection
OpenAiProvider.api_keyZeroizing<String>
AnthropicProvider.api_keyZeroizing<String>
GoogleProvider.api_keyZeroizing<String>
Drop behaviorMemory zeroed on Drop via zeroize crate
Compiler optimizationzeroize uses core::ptr::write_volatile to prevent dead-store elimination

Engram memory content encryption

Project Engram adds field-level PII encryption for memory content. Unlike credential zeroing (above), this protects the actual memories stored by agents — not just API keys.

PII detection

Before storage, every memory passes through a two-layer PII scanner with 17 regex patterns:
#PatternExampleTier
1Social Security Numbers123-45-6789, 123456789Confidential
2Credit card numbers4111-1111-1111-1111Confidential
3Email addressesuser@example.comSensitive
4Phone numbers+1-555-0123Sensitive
5International phone numbers+44 20 7946 0958Sensitive
6Physical addressesStreet address patternsSensitive
7Person namesMr./Mrs./Dr. prefixed namesSensitive
8Geographic locationsCity/state/country patternsSensitive
9Government IDsPassport, driver’s licenseConfidential
10JWT tokenseyJhbGciOi... (header.payload.signature)Confidential
11AWS access keysAKIA... (20-char key IDs)Confidential
12Private keys (RSA/EC/DSA)-----BEGIN ... PRIVATE KEY-----Confidential
13IBANGB82 WEST 1234 5698 7654 32Confidential
14IPv4 addresses192.168.1.1Sensitive
15Generic API keyssk-, api_key=, Bearer tokensConfidential
16Credentials (passwords)password=, secret= patternsConfidential
17Dates of birth1990-01-15Sensitive
Layer 2 (planned): LLM-assisted secondary scan for context-dependent PII that static regex cannot catch.

Encryption details

PropertyDetail
AlgorithmAES-256-GCM (authenticated encryption)
Key storageOS keychain via keyring crate (service: paw-memory-vault)
GranularityField-level — only PII-containing content is encrypted
Formatenc:base64(nonce ‖ ciphertext ‖ tag)
DecryptionTransparent on retrieval — callers see plaintext
Tier classificationCleartext (no PII) / Sensitive (encrypted) / Confidential (encrypted)

Query sanitization

All search queries are sanitized before reaching the storage backend to prevent injection:
  • Search operators (AND, OR, NOT, NEAR, *, ", (, )) are stripped
  • Column filter syntax (:) is removed
  • Empty queries after sanitization are rejected

Prompt injection scanning

Memory content is scanned against 10 known prompt injection patterns before storage. Matches are redacted with [REDACTED:injection] markers, preventing poisoned memories from manipulating agent behavior on future recalls.

GDPR Article 17 — Right to erasure

The gdpr_purge command performs a complete data erasure for a user:
  1. All memory content rows deleted
  2. All vector embeddings deleted
  3. Search index entries removed
  4. Graph edges removed
  5. Padding table repacked to prevent file-size leakage
  6. PRAGMA secure_delete ensures freed pages are zeroed

Inter-agent memory bus trust

The cross-agent memory bus (pub/sub for sharing memories between agents) enforces publish-side authentication to prevent memory poisoning.

Capability tokens

Each agent holds an AgentCapability signed with HMAC-SHA256 against a platform-held secret key. The token specifies:
  • Max publication scope — Agent, Squad, or Global
  • Importance ceiling — Maximum importance an agent can assert (0.0–1.0)
  • Write permission — Whether the agent can publish at all
  • Rate limit — Maximum publications per GC window
Every publish() call verifies the token signature in constant time before any bus operation.

Publish-side defenses

DefenseDetail
Scope enforcementPublication scope clamped to agent’s maximum — cannot publish beyond assigned authority
Importance ceilingPublication importance clamped to agent’s ceiling — prevents low-trust agents from asserting high-confidence facts
Per-agent rate limitingPublish count tracked per GC window — exceeding limit returns MemoryBusRateLimit error
Injection scanningAll publication content scanned for prompt injection patterns before entering the bus

Trust-weighted contradiction resolution

When two agents publish contradictory facts on the same topic, the system resolves based on trust-weighted importance:
effective_importance = raw_importance × agent_trust_score
The memory with the higher effective importance is retained. Trust scores are per-agent (0.0–1.0) and adjustable at runtime. This prevents a compromised low-trust agent from overwriting facts established by high-trust agents.

Threat model

AttackMitigation
Agent floods bus with poisoned memoriesRate limit + injection scan on publish side
Low-trust agent overwrites high-trust factsTrust-weighted contradiction resolution
Agent publishes beyond its authority scopeScope ceiling enforcement
Forged capability tokenHMAC-SHA256 verification against platform secret

Anti-forensic vault-size quantization

The Engram memory store mitigates vault-size oracle attacks — a side-channel where an attacker can infer how many memories are stored by observing the SQLite database file size. This is the same threat class addressed by KDBX inner-content padding.

What this prevents

An attacker with read-only access to the filesystem (malware, backup exfiltration, shared-machine forensics) cannot determine:
  • Exact number of stored memories
  • Whether memories were recently deleted (no file-size drop)
  • Growth rate of the knowledge store over time

Implementation

MitigationDetail
Bucket paddingDB padded to 512KB boundaries via _engram_padding table (zeroblob rows). Re-padded after every GC cycle.
Secure erasureTwo-phase delete: content fields overwritten with empty values → row deleted. Prevents plaintext recovery from freed pages or WAL replay.
8KB page sizePRAGMA page_size = 8192 reduces file-size measurement granularity
Secure deletePRAGMA secure_delete = ON zeroes freed B-tree pages at the SQLite layer
Incremental auto-vacuumPRAGMA auto_vacuum = INCREMENTAL prevents immediate file-size shrinkage after deletions

Threat model comparison

PropertyKDBX (KeePass 4.x)Engram (SQLite)
Content encryptionFile-level (ChaCha20/AES-256)Field-level (AES-256-GCM)
Size paddingInner XML padded to block boundaryDB padded to 512KB bucket
Delete forensicsZeroed inner streamTwo-phase overwrite + secure_delete
Metadata leakageFixed-size headerQuantized file size

Tool execution security

Tool execution is governed by multiple safety mechanisms in the engine’s central tool executor.

Source code introspection block

Agents cannot read engine source files — any read_file call targeting paths containing src-tauri/src/engine/, src/engine/, or files ending in .rs is rejected. This prevents agents from exfiltrating their own implementation details or discovering internal security mechanisms.

Credential write block

The write_file tool blocks content that contains credential-like patterns:
  • PEM private keys (-----BEGIN ... PRIVATE KEY-----)
  • API key secrets (api_key_secret, cdp_api_key)
  • Base64-encoded secrets with secret or private keywords

Execution limits

SettingDefaultDescription
maxToolCallsPerTurnPer-agent policyMaximum tool calls an agent can make in a single turn before being stopped
tool_timeout_secs300Seconds before a pending tool approval or execution is killed
max_tool_rounds20Maximum tool-call → result → re-prompt loops per turn
max_concurrent_runs4Maximum simultaneous agent runs

Output truncation

Tool results are capped to prevent context window overflow:
ToolMax outputBehavior
exec50,000 charsTruncated with [output truncated] marker
read_file32,000 charsTruncated with total byte count
fetch50,000 charsTruncated with total byte count
Container sandbox50,000 chars (stdout + stderr each)Truncated with [stdout/stderr truncated] marker

Network policy enforcement

The fetch tool enforces domain-level network policy — blocked domains are always rejected, and when an allowlist is active, only listed domains are permitted.

Exfiltration detection

Outbound network commands are audited for data exfiltration patterns:
  • Piping file contents to curl, wget, or nc
  • File upload flags (curl -T, curl --data-binary @, wget --post-file)
  • Redirects to /dev/tcp/
  • scp and rsync to remote hosts
:::warning Exfiltration detection is pattern-based and applies to exec tool invocations. It supplements — but does not replace — the container sandbox for high-security environments. :::

Budget enforcement

Daily spending limits with progressive warnings:
ThresholdAction
50%Warning
75%Warning
90%Warning
100%Requests blocked

Trading safety

ControlDefault
Auto-approve tradesOff
Max trade size$100
Max daily loss$500
TransfersDisabled
Max transfer$0

Channel access control

PolicyBehavior
OpenAnyone can chat
AllowlistOnly approved users
PairingUsers must pair with a code
Each user gets an isolated session — no cross-user data leakage.

Reporting vulnerabilities

See SECURITY.md in the repository for reporting instructions.