Culprit

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 / 07 — Tokenization

How tokenization works

PAYLOADENCRYPTTO LLMAUTHORIZEDhost:db-prod-7user:alice@acmekey: sk-9f2…pgp_sym+ rlshost:<HOST_a3f9>user:<EMAIL_4d2c>key: <KEY_e8b1>host:db-prod-7user:alice@acmekey: sk-9f2…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 — email addresses, IP addresses (v4 + v6), internal hostnames, secrets and API keys, identifiers (UUIDs, hashes, tokens), credit cards, SSNs, and any custom patterns you configure — 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.

For the long-form walkthrough — why the obvious fixes (strip-on-write, drop-on-detect, redact-in-prompt) all leak, and the four hard parts of building this pipeline yourself — see How to keep PII out of your alert pipeline.

02 / 07 — 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 / 07 — 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 / 07 — AI safety

AI safety and prompt injection

Root-cause analysis runs an LLM over your alert data, so a hostile payload in your pipeline could try to manipulate the model. Prompt injection is an open research problem; we do not claim to have solved it. What we have done is bound the blast radius.

The model only ever sees the tokenized event — PII has already been replaced with <TOKEN_…> placeholders before the prompt is built. The RCA call has no tool use, no function-calling, no internet access, and a hard max_tokens cap; output is constrained to a JSON schema. RAG retrieval over prior incidents is pinned to the calling tenant at the SQL predicate. Generated text is rendered as plain React children with markdown links stripped at dispatch — never via dangerouslySet-prefixed props, which an ESLint rule blocks repo-wide.

That posture makes a few outcomes structurally impossible: a poisoned alert cannot exfiltrate raw PII (the model never sees it), execute XSS against our UI (no HTML sink exists), or read another tenant’s data (the RAG predicate forecloses it). Casual ignore previous instructions jailbreaks are also reliably caught.

What the layered defense reduces but does not eliminate: a customer-internal attacker — a compromised source system, a malicious insider, or a poisoned upstream log line — can shape an RCA narrative that misleads an on-call into the wrong remediation. No LLM-bearing architecture fully closes that door. Your upstream control over what reaches /v1/ingest is the first line; on our side, thumbs-down feedback excludes a bad RCA from the RAG corpus, and every analysis call lands in an append-only audit log.

05 / 07 — Compliance

Compliance posture

Culprit’s data-handling controls — encryption-at-rest, tenant isolation by RLS, audit logging via pgaudit, documented incident response — align with SOC 2 Type II common criteria and HIPAA technical safeguards. We are not yet certified/attested. Our attestation roadmap and a BAA template are available on request for prospective customers whose compliance requirements make this material.

A HIPAA Business Associate Agreement is available for HIPAA-covered entities on request — contact legal@theculprit.ai.

06 / 07 — Vendors

Vendors and what they see

Six subprocessors touch the data path. None of them see raw incident 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.
PaddleMerchant-of-record billing. Receives the account-owner’s name, billing address, payment-method token, and transaction history — never sees incident PII or the tokenization keys.

07 / 07 — 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 d9b5312updated 2026-06-09no trackersno analyticsno third-party scripts