Zilla CRM
Security & controls
Plain-language summary of controls documented in the zilla-crm codebase. This page does not describe marketing-site hosting, only CRM agent and delivery mechanics.
Early access status: delivery is test_only during early access (see crm_0002_policy.sql). Email delivery is test-only, not production bulk sending.
01 / Per-tenant runtime tokens
Tokens are random; only the SHA-256 hash is stored, tenant-bound in SQL, revocable, and issuable only by service_role.
packages/db/migrations/crm_0011_agents.sql
02 / No provider keys in agents
The agent holds one runtime token. Every read and write goes through the host tool API POST /crm/agent. The gateway strips client auth headers and holds the model key.
runtime/README.md · runtime/gateway.py · runtime/tenant.sh
03 / Network lockdown
Internal-only Docker network. The gateway allows exactly two endpoints (the model API /v1/messages and POST /crm/agent), checked by a network probe. Containers are read-only, non-root, drop all capabilities, no-new-privileges, base image pinned by digest, packages hash-locked.
runtime/tenant.sh · runtime/gateway.py · runtime/netprobe.py · runtime/Dockerfile
04 / Locked-down agent
All built-in tools, memory and plugins are off; the agent can reach only the CRM's own tool server, one tool per run. Each run uses a fresh scratch home and fails closed on tool mismatch. The DB enforces tools per agent: Insights can only write recommendations and notes; email agents can only write or revise email.
runtime agent config · runtime/crm_runtime/policy.py · runtime/crm_runtime/launcher.py · packages/db/migrations/crm_0011_agents.sql
05 / Content checks
Every email version is checked for price, link, offer, stock, superlative, spam, shouting, number, and restricted content. Agents are denied; people are flagged. Human approval never overrides a deny.
packages/core/src/content-check.ts · packages/db/migrations/crm_0004_messages.sql
06 / Approval bound to content hash
Each approval is bound to an exact message version via SHA-256 over content, audience, sender, schedule, products, and policy. Any edit requires a new approval.
packages/db/migrations/crm_0004_messages.sql
07 / Agent modes and ceilings
Modes order: off < draft < approve < auto. Each agent has a hard maximum (Insights draft-only; Prospect maxes at Approve and starts Off). Effective mode is the lowest of client setting, policy ceiling, and hard max.
packages/db/migrations/crm_0002_policy.sql
08 / Kill switches and delivery brakes
Pause everything, all campaigns, or one agent. Automatic brakes pause the tenant at 0.08% complaints or 4% hard bounces over 30 days (minimum 50 sends). The console can only tighten those limits.
packages/db/migrations/crm_0002_policy.sql · packages/db/migrations/crm_0008_delivery.sql
09 / Append-only audit log
A trigger refuses UPDATE and DELETE; each row records actor type and actor.
packages/db/migrations/crm_0002_policy.sql
10 / Consent ledger
Consent per tenant, address, dealer, channel, and category, with evidence. Never inferred (no row means no). Ledger is append-only; opt-out lifts only via the recipient’s new opt-in.
packages/db/migrations/crm_0003_consent.sql
11 / RFC 8058 unsubscribe
One-click unsubscribe. GET shows a confirm page so link scanners cannot unsubscribe anyone. Tokens carry 244 random bits.
packages/host-next/src/unsubscribe.ts
12 / Bounces and complaints
Hard bounces and provider suppressions are never deleted. A complaint counts as a global withdrawal.
packages/db/migrations/crm_0008_delivery.sql
13 / Weekly send cap
Per-recipient weekly cap reserved atomically under row locks.
packages/db/migrations/crm_0005_sends.sql
14 / Signed delivery webhooks
URL and secret per tenant. Signature verified over raw bytes; DB checks tenant; processing is idempotent.
packages/host-next/src/webhook.ts
15 / Database lockdown
No grants to anon or authenticated. RLS on every table. Functions granted explicitly.
packages/db/migrations/crm_0001_foundation.sql
Questions about your deployment? Early access form or al@zilla.wtf.