TL;DR - The Short Answer
TL;DR — The Short Answer Cole secures multi-tenant AI agent data using five isolation layers: (1) PostgreSQL Row-Level Security (RLS) on every table, enforced via JWT tenant_id claims; (2) API middleware that validates tenant context before any database operation; (3) sealed, signed worker context tokens that travel with every background job; (4) LLM prompt boundaries that explicitly scope the AI to the current tenant; and (5) output sanitization that strips cross-tenant data leakage before any response reaches the user. Sensitive tokens are encrypted with AES-256-GCM, secrets live in Doppler (never .env files), and all traffic runs over TLS 1.3.
When you give every customer their own persistent AI agent—one that remembers their team, manages their tasks, reads their messages, and speaks in their voice—the stakes around data isolation go from important to existential.
A single cross-tenant data leak doesn't just violate a privacy policy. It destroys the trust that makes an AI chief of staff useful in the first place. If your agent accidentally surfaces Company A's quarterly revenue in Company B's Slack thread, you don't have a bug. You have a company-ending event.
This is the problem we had to solve at Pocodot when building Cole, our multi-tenant AI Chief of Staff SaaS. Cole lives in WhatsApp, Slack, and Telegram. He manages tasks, stores memory, coordinates teams, and executes voice briefings—all for thousands of separate organizations sharing the same infrastructure.
This post walks through the five-layer defense-in-depth architecture we built to ensure that no tenant ever sees another tenant's data—even if an attacker compromises one layer entirely.
Why Is Multi-Tenant AI Security Harder Than Traditional SaaS?
Traditional multi-tenant SaaS applications have a well-understood threat model: isolate database rows, scope API requests, and encrypt at rest. AI agents introduce three additional attack surfaces that most security frameworks don't address:
- Memory persistence: Cole stores long-term memory per tenant—preferences, contact info, decisions, task history. A memory leak between tenants exposes months of business context, not just a single request.
- LLM context window: Every conversation with the AI model includes system prompts, conversation history, and tool results. If tenant context bleeds into another tenant's prompt, the LLM will cheerfully use it.
- Prompt injection: A malicious user in Tenant A could craft a message designed to trick the AI into revealing information from its system prompt or other tenants' data. This isn't hypothetical—it's the #1 OWASP risk for LLM applications.
The solution isn't a single wall. It's five walls, each independent, so that a breach in one layer doesn't cascade.
Layer 1: Row-Level Security — The Database Knows Who You Are
The most fundamental isolation happens at the PostgreSQL layer itself. Cole uses Supabase's Row-Level Security (RLS) to ensure that every query is automatically scoped to the requesting tenant. This means even if application code has a bug that forgets a WHERE clause, the database itself refuses to return another tenant's rows.
Here's the actual pattern. RLS is enabled on every tenant-scoped table:
-- Enable RLS on all tenant-scoped tables
ALTER TABLE tenants ENABLE ROW LEVEL SECURITY;
ALTER TABLE team_members ENABLE ROW LEVEL SECURITY;
ALTER TABLE tasks ENABLE ROW LEVEL SECURITY;
ALTER TABLE conversations ENABLE ROW LEVEL SECURITY;
ALTER TABLE memory ENABLE ROW LEVEL SECURITY;
-- Policy: team members scoped to tenant
CREATE POLICY team_members_tenant ON team_members
USING (tenant_id IN (
SELECT id FROM tenants WHERE owner_user_id = auth.uid()
));The critical detail here is auth.uid()—this pulls the authenticated user's ID directly from the Supabase JWT, not from any application-level parameter that could be tampered with. Even a compromised API endpoint cannot bypass RLS because the database enforces it at the connection level.
This applies to five core tables: tenants, team_members, tasks, conversations, and memory. Every piece of data Cole touches—from a task assignment to a stored preference—is RLS-protected.
Layer 2: API Middleware — Validating Tenant Context Before Any Operation
RLS is the safety net. The API middleware is the first line of defense. Every inbound request—whether it's a webhook from WhatsApp, an API call from the dashboard, or an internal worker request—goes through tenant authentication middleware before touching the database.
async function tenantAuthMiddleware(req: Request) {
// 1. Extract JWT from Authorization: Bearer
const jwt = extractBearerToken(req);
if (!jwt) throw new APIError(401, 'UNAUTHORIZED');
// 2. Verify with Supabase Auth
const { user, error } = await supabase.auth.getUser(jwt);
if (error || !user) throw new APIError(401, 'INVALID_TOKEN');
// 3. Load tenant from DB (cached 60s in Redis)
const tenant = await getTenantForUser(user.id);
if (!tenant) throw new APIError(403, 'NO_TENANT');
if (tenant.is_suspended) throw new APIError(403, 'TENANT_SUSPENDED');
// 4. Attach to request context
req.context = { user, tenant };
}Notice step 3: tenant resolution is cached in Redis for 60 seconds to keep latency low, but the underlying verification always comes from the database. If a tenant is suspended (for non-payment, abuse, or any other reason), the middleware immediately blocks all operations—the AI agent goes silent until the issue is resolved.
Layer 3: Sealed Worker Context — Background Jobs Can't Cross Boundaries
Cole processes most work asynchronously. When a message arrives on WhatsApp, it's normalized into an internal envelope and dispatched to a BullMQ job queue. The worker that picks up that job needs to know which tenant it's operating for—but it can't be allowed to reach into any other tenant's data.
The solution is a sealed, signed tenant context token that travels with every job:
interface TenantContext {
tenant_id: string;
org_name: string;
tier: 'free' | 'starter' | 'team' | 'executive' | 'enterprise';
worker_slots: number;
}This context is signed at dispatch time and verified by the worker before any processing begins. The worker cannot modify the tenant_id, fabricate a different context, or operate outside its assigned tenant scope. If the signature doesn't match, the job is rejected and routed to the dead-letter queue, which triggers a PagerDuty alert.
Layer 4: LLM Prompt Boundaries — The AI Itself Knows Its Limits
Even with perfect database and API isolation, the LLM needs to be explicitly told its scope. Understanding how AI agents differ from chatbots helps explain why this layer is critical—agents have persistent memory and tool access that chatbots lack. Cole's system prompt is dynamically constructed per tenant, per session, and includes explicit tenant boundary instructions:
- The system prompt states the tenant's organization name and scope explicitly
- All user input is sanitized before injection into prompts, using XML-style delimiters to separate instructions from user content
- Agent tools have input validation at the execution layer—not just the prompt layer
- A rate limit on tool calls per turn prevents runaway agents from making excessive requests
For email integration specifically, where content is untrusted external data, Cole wraps all email bodies in XML delimiters before the LLM processes them:
function sanitizeEmailContent(body: string): string {
const text = stripHtml(body);
return `<user_email_content>${text}</user_email_content>`;
}This prevents a crafted email from injecting instructions into Cole's prompt—a real attack vector that has compromised other AI assistant products in production.
Layer 5: Output Sanitization — Nothing Leaves Without Inspection
The final layer is a sanitization function applied to every piece of content Cole sends back to any channel—WhatsApp, Slack, Telegram, email, or the web dashboard:
sanitizeOutput(text: string): string
// Strips: file paths, API keys, internal refs,
// cross-tenant identifiers, system prompt fragments
// Applied to ALL agent output before delivery
// No exceptions.This catches the edge cases that even well-scoped prompts can miss. If the LLM hallucinates a file path, references an internal API key from its training data, or accidentally includes a reference to another tenant's name, the sanitizer catches it before it reaches the user.
How Does Cole Address the OWASP Top 10?
Security isn't just about tenant isolation. When choosing the right AI agent platform, security architecture should be a top evaluation criterion. Cole's architecture maps directly to the OWASP Top 10 web application security risks:
| OWASP Threat | Cole's Mitigation |
|---|---|
| Injection | Parameterized queries only via Supabase JS SDK. No raw SQL with user input, ever. |
| Broken Authentication | Supabase Auth JWTs for user sessions + HMAC-SHA256 signature verification on all webhooks. |
| Sensitive Data Exposure | AES-256-GCM encryption for OAuth tokens at rest. TLS 1.3 for all data in transit. Encrypted at-rest storage. |
| XML External Entities | Not applicable—Cole is a JSON-only API. No XML parsing surface. |
| Broken Access Control | RLS on every table + API middleware tenant check. Double enforcement. |
| Security Misconfiguration | All secrets managed in Doppler (not .env files). Automated security scans in CI pipeline. |
| Cross-Site Scripting | React auto-escapes output by default. Content Security Policy (CSP) headers set on all responses. |
| Insecure Deserialization | JSON.parse applied only to trusted internal messages. No arbitrary deserialization of user input. |
How Are Secrets and Tokens Managed?
Cole integrates with WhatsApp Business API, Slack, Telegram, and Google Workspace. Each integration requires OAuth tokens that are extremely sensitive—a leaked Slack token could give an attacker access to an entire organization's workspace.
- Encryption: All channel OAuth tokens are encrypted with AES-256-GCM before database storage. The encryption key is rotated quarterly, with old keys retained for decryption of existing tokens.
- Secret management: All production secrets are stored in Doppler, which syncs to the DigitalOcean droplet environment at boot. No .env files in production—ever.
- Log hygiene: Middleware strips Authorization headers from all logs. No secrets appear in Sentry error reports, Axiom log streams, or any observability tool.
- Cross-tenant token isolation: Tokens are loaded per-job from the database, scoped to the current tenant_id. A worker processing Tenant A's job never has Tenant B's tokens in memory.
What About GDPR, Data Retention, and Compliance?
Multi-tenant AI agents handle some of the most sensitive business data imaginable—meeting notes, task assignments, team performance, internal communications. Cole's compliance posture reflects that:
- GDPR: Data deletion within 30 days of account cancellation. Full right to data export. Data Processing Agreement (DPA) available for enterprise customers.
- TCPA: Explicit consent required before any outbound voice calls, logged with timestamp and consent reference ID.
- Data retention: Conversation history retained for 90 days (configurable per tenant). Audit logs retained for 7 years. Voice call recordings retained for 30 days.
- SOC 2: Type I audit targeted at 100 customers. Type II at 500 customers.
- Webhook verification: Every inbound webhook (WhatsApp, Slack, Stripe) is verified with HMAC-SHA256 using timing-safe comparison to prevent replay and spoofing attacks.
The Full Picture: Cole's Request Flow
Every inbound message—whether from WhatsApp, Slack, or Telegram—passes through the same hardened pipeline:
| Step | Component | Security Function |
|---|---|---|
| 1 | Webhook Receiver | HMAC signature verification. Rejects unverified payloads. |
| 2 | Tenant Resolver | Looks up tenant by channel identity. Enforces tenant isolation at the entry point. |
| 3 | Rate Limiter | Per-tenant, per-channel sliding window via Redis token bucket. Prevents abuse and DoS. |
| 4 | Message Normalizer | Standardizes to internal MessageEnvelope format. Strips channel-specific artifacts. |
| 5 | Dispatcher + Queue | Enqueues to BullMQ with sealed tenant context, priority, and idempotency key. |
| 6 | Worker + LLM | Loads tenant context, builds scoped system prompt, processes via Claude with prompt boundaries. |
| 7 | Output Sanitizer | Strips file paths, API keys, internal refs, cross-tenant identifiers. Applied to all output. |
Frequently Asked Questions
Can one tenant's data ever leak into another tenant's AI conversations?
No. Cole uses five independent isolation layers—Row-Level Security at the database, API middleware validation, sealed worker contexts, LLM prompt boundaries, and output sanitization. Each layer operates independently, so even if one is compromised, the remaining four prevent cross-tenant data exposure.
How does Cole encrypt sensitive data like OAuth tokens?
All channel OAuth tokens (WhatsApp, Slack, Telegram, Google Workspace) are encrypted with AES-256-GCM before database storage. Encryption keys are rotated quarterly, and old keys are retained only for decryption. Tokens are never logged, and middleware strips Authorization headers from all observability tools.
Is Cole GDPR compliant?
Yes. Cole supports data deletion within 30 days of account cancellation, provides full data export capabilities, and offers a Data Processing Agreement (DPA) for enterprise customers. Conversation history is retained for a configurable period (default 90 days), and audit logs are retained for 7 years.
How does Cole prevent prompt injection attacks?
Cole sanitizes all user input before injecting it into LLM prompts, using XML-style delimiters to separate system instructions from user content. External data sources like email bodies are wrapped in tagged boundaries. Additionally, agent tools have input validation at the execution layer, and rate limits on tool calls per turn prevent runaway agent behavior.
What happens to my data if I cancel my Pocodot account?
All tenant data—including tasks, conversations, memory, team member records, and channel connections—is deleted within 30 days of cancellation. This deletion cascades through all related tables via foreign key constraints. Before cancellation, you can request a full data export.
Ready to try an AI Chief of Staff that takes security seriously?
Cole is free to start—no credit card required. You get 100K tokens/month on the free tier, with the same five-layer security architecture protecting your data from day one. Learn more about how credits work and get started at pocodot.ai/cole.
