logicspike/docs

Chat Engine

Security & Privacy Spec (Trust & Safety)

Last Updated: 2026-03-31 Status: Active

This document outlines the strict data privacy, multi-tenant boundaries, and cryptographic security measures implemented within the Chat Engine. Since the system ingests proprietary business documents (Knowledge Hub) and handles end-user chats (PII), security is our highest priority.


1. Multi-Tenant Data Isolation

1.1 pgvector Semantic Isolation

Vector databases are prone to "cross-tenant leakage" if queries are not rigorously filtered.

Invariant: Every vector similarity search MUST enforce a hard WHERE tenant_id = ? clause at the lowest SQL execution level.

-- DANGEROUS (NEVER DO THIS):
SELECT raw_text FROM knowledge_chunks ORDER BY embedding <-> '[0.1, ...]' LIMIT 5;
 
-- CORRECT:
SELECT raw_text FROM knowledge_chunks 
WHERE tenant_id = 'tnt_123' 
ORDER BY embedding <-> '[0.1, ...]' LIMIT 5;

If we fail to enforce this, Tenant A's pricing guide could be fed into the LLM when Tenant B's customer asks a question.

1.2 Redis Memory Isolation

Chat histories stored in Redis for fast caching must use prefixed keys that include both the tenantId and sessionId.

  • Format: chat:{tenantId}:session:{sessionId}:history
  • This ensures that a bug regarding identical sessionIds across different accounts cannot result in cross-account chat history loading.

2. Cryptographic Security for Third-Party Channels

The Chat Engine connects to logic outside of LogicSpike via Meta, Telegram, and standard Webhooks.

2.1 The Credentials Store

When a Business Owner connects their WhatsApp Business API, they provide a long-lived Access Token.

Rule: ChannelIntegration.credentials is NEVER stored in plain text.

  • Before INSERT/UPDATE, the token is encrypted using AES-256-GCM.
  • The decryption key is held strictly in environment variables (ENCRYPTION_SECRET), injected only at runtime into the chat-service memory.
  • The Dashboard Frontend NEVER receives the plaintext token back in a GET request. It only receives {"status": "active", "has_token": true}.

2.2 Ingress Webhook Verification

We cannot trust payloads simply because they strike our /webhooks/whatsapp endpoint.

Rule: Every incoming WhatsApp webhook must be cryptographically verified using crypto.createHmac.

  • Meta signs the HTTP body with the App Secret.
  • The X-Hub-Signature-256 header must match our newly generated HMAC checksum of the raw request body.
  • If it fails, we drop the connection with a 401 Unauthorized. This prevents malicious actors from spoofing messages from customers to inflate LLM token billing costs.

3. PII (Personally Identifiable Information) Redaction

Customers frequently send credit card numbers, social security numbers, or sensitive medical info to chatbots, assuming it is human and secure.

LLM PII Bleed Prevention

Before the Chat Orchestrator sends a customer's message to the external LLM provider APIs (OpenAI / Gemini), a Regex-based PII scrubber intercepts the payload:

  • Credit cards, generic regex: replaced with [REDACTED_CARD]
  • SSNs, generic regex: replaced with [REDACTED_ID]

This ensures we do not train foundational models on our customers' sensitive data, maintaining SOC2 compliance.


4. LLM API Key Rotation & Zero-Trust

The chat-service communicates continuously with OpenAI/Gemini.

  • Key Storing: The primary OPENAI_API_KEY is rotated every 30 days via Cloudflare Secrets.
  • Provider Opt-Out: LogicSpike exclusively uses enterprise-tier LLM endpoints that legally guarantee zero retention of our prompt data (OpenAI API Data Privacy policy), meaning Tenant data is not used to train the general ChatGPT model.

5. Widget CORS & Origin Validation

The embeddable Website Widget loads inside a sandboxed <iframe> on third-party domains. Strict origin controls prevent abuse.

  • Allowed Origin: When a tenant enables the Widget channel, they register their domain (e.g., https://rahuls-saas.com). The ChannelIntegration.identifier stores this domain.
  • Validation Flow: Every POST /chat/widget/message request includes an Origin header. The Chat Service checks: Does the X-Widget-Token belong to a ChannelIntegration whose identifier matches this Origin? If not → 403 FORBIDDEN.
  • Why This Matters: Without this, an attacker could copy the <script> tag, embed it on their own site, and burn through the tenant's AI credits by sending thousands of junk messages.

6. Per-Tenant Rate Limiting

To prevent a single workspace from accidentally (or maliciously) overwhelming the system:

Scope Limit Window Action on Breach
Widget Messages (per session) 30 messages 1 minute Return 429 RATE_LIMIT_EXCEEDED. Show friendly: "You're typing too fast! Please wait a moment."
Webhook Ingress (per tenant) 200 messages 1 minute Enqueue normally but flag the tenant for review.
Dashboard API (per user) 100 requests 1 minute Return 429. Standard API protection.
LLM Token Budget (per tenant) Configurable monthly cap 30 days Return 402 CREDIT_EXHAUSTED. All sessions auto-escalate to human_escalated.
Chat Engine