Document — Culprit Security Posture

Security

Culprit is built around the premise that you should be able to send us your alerts without also sending us your customer data. Here’s how that actually works in practice.

01 / 06 — Tokenization

How tokenization works

WEBHOOK/ INGRESSVAULT/ ENCRYPTEDAI/ CORRELATIONINCIDENT/ UI
Fig 02 — Tokenization pipeline

Alerts arrive at a Cloudflare Worker that authenticates the sender, encrypts the raw payload with pgp_sym_encrypt, and parks it in a vault table keyed to your tenant. The edge handler returns 200 OK and enqueues the work — no downstream system sees plaintext on the ingest path.

A detector then walks the payload for PII and ePHI (emails, IPs, hostnames, account names, free-text) and swaps each match for a <TOKEN_…> placeholder. The original value is encrypted into a per-tenant token dictionary; the sanitized event is what flows into correlation, LLM prompts, logs, and notifications. Rehydration is a single route — an authenticated reveal endpoint that checks tenant scope on every request before decrypting — and every reveal writes to the audit log.

02 / 06 — Data

Data handling

Four classes of data, four different retention and encryption regimes.

DataLocationEncryptionRetention
Raw alert payloadsraw_alerts_vaultpgp_sym_encrypt (AES-256)Active: indefinite / Closed: 30d
Tokenized eventssanitized_eventsAt-rest (Postgres TDE)90 days rolling
Token dictionarytoken_dictionarypgp_sym_encrypt (per-tenant key)Matches parent incident
Audit logsaudit_log (pgaudit)At-rest, append-only7 years (SOC2/HIPAA aligned)

03 / 06 — Isolation

Tenant isolation

Every tenant-scoped table has Row-Level Security enabled, and every policy pins reads and writes to auth.uid()’s tenant membership. The application layer never queries with the Supabase service-role key on a user-facing path — that credential is quarantined to a narrowly scoped admin wrapper that asserts an internal x-admin-verified header set by our middleware. An ESLint rule blocks direct service-role imports in the web app, so a fresh session cannot silently reintroduce a bypass. Tenant crossover is a database-level impossibility, not a convention we trust humans to follow.

04 / 06 — Compliance

Compliance posture

Culprit is architected for SOC2 Type II and HIPAA obligations — encryption-at-rest, tenant isolation by RLS, audit logging via pgaudit, and a documented incident-response process. We are not yet certified/attested. A BAA template is available on request for pilot customers handling PHI; our attestation roadmap (auditor engagement, SOC2 Type I → Type II timeline) is available on request to prospective customers.

05 / 06 — Vendors

Vendors and what they see

Five subprocessors touch the data path. None of them see raw PII.

VendorWhat they see
SupabaseEncrypted payloads and tokenized events at rest. Postgres instance is tenant-isolated via RLS. No vendor employee holds a per-tenant decryption key.
CloudflareInbound webhook bodies transit Workers for HMAC verification, then move to Queues as encrypted blobs. Worker logs contain only tokens.
AnthropicReceives tokenized incident context for root-cause analysis. Prompts contain <TOKEN_…> placeholders only. Zero Data Retention is enabled on the API key.
OpenAIReceives tokenized events for embedding. Placeholders only; raw values never leave Postgres. Inputs are not retained for training.
ResendTransactional email (invite links, password resets). Recipient address and the tokenized message body — no incident PII in subject or body.

06 / 06 — Incident response

Incident response

In the event of a confirmed breach affecting customer data, we notify affected tenants within 72 hours of discovery — consistent with HIPAA breach-notification rules and GDPR-style timelines. Notifications include the scope of the incident, the data classes involved, and the remediation status. Security researchers and customers can reach the security team at:

security@theculprit.ai

build 0ebe0a4updated 2026-04-20no trackersno analyticsno third-party scripts