Security

Concrete measures — not marketing claims — protecting every account and every pilot deployment. Audited during our launch readiness review on 2026-04-17.

Encryption

  • In transit: TLS 1.3 on every public endpoint. HTTP Strict Transport Security (HSTS) enforced with a 2-year max-age and includeSubDomains preload.
  • At rest: AES-256 on the application database (Supabase-managed Postgres 17). File uploads encrypted at rest in Supabase Storage.
  • Secrets: API keys and webhook secrets are never logged. Application secrets live in Vercel environment variables, segregated per environment.

Access control & data isolation

  • Row Level Security (RLS) is enabled on every table holding user data — profiles, conversations, messages, API keys, violations, moderation logs, safety events, billing transactions, user memories. Each policy scopes reads to auth.uid() = user_id.
  • API keys are stored as SHA-256 hashes only; raw keys are shown once at creation. Lookups happen against the hash.
  • Customer isolation: Cross-tenant reads are technically impossible through the public API. Admin client usage is limited to billing / security / webhook paths and always filters by user_id explicitly — defense in depth on top of RLS.
  • Max 3 active API keys per user, enforced at the database level via a trigger, not an application-level check.

Authentication

  • Supabase Auth with password hashing via bcrypt.
  • Google OAuth supported for customers who prefer SSO.
  • Session cookies are HttpOnly, Secure, and SameSite=Lax.
  • Optional two-factor authentication on the user profile.
  • Post-auth redirects are validated as same-site paths — no open-redirect exposure.

Moderation & abuse prevention

  • Every chat message passes through a layered pipeline: rate-limit check, input sanitization, OpenAI Moderation API, local jailbreak regex, progressive violation penalties.
  • Default-deny posture: when a security dependency (Redis, Supabase) is unavailable, requests return 503 Service Unavailable rather than bypassing checks.
  • Progressive violation penalties: 10 min → 1 hour → 24 hour → 7 day → permanent. Zero tolerance for CSAM, terrorism, credible threats against persons, or content sexualizing minors.
  • Rate limits enforced per user, per endpoint, and per client IP through Upstash Redis, with a bounded in-memory fallback if Redis is unavailable.

Crisis-safety webhooks

  • Per-key pattern detection for suicide ideation, self-harm, first-person abuse disclosure, child-at-risk signals, and explicit violent threats.
  • Events delivered to your HTTPS endpoint with an X-JCIL-Signature: sha256=… header; verify with HMAC-SHA256 over the raw body.
  • Webhook URLs must use https://; the application rejects non-TLS targets.
  • Webhook dispatch happens after the response finishes streaming so it never delays the visitor's answer.

Billing & payment security

  • All payments flow through Stripe. JCIL.AI never receives card numbers; we're out of PCI-DSS scope.
  • Stripe webhooks are verified with Stripe's signed payload and de-duplicated by session.id so retries cannot double-credit.
  • Atomic charge + monthly-cap checks live in a single Postgres function to prevent race conditions under concurrent chat requests.

Vulnerability disclosure

If you believe you've found a security issue in JCIL.AI, please report it through the compliance contact form with topic: security. We respond within 48 hours, acknowledge good-faith reporters, and do not pursue legal action against researchers following coordinated disclosure.

Machine-readable disclosure info lives at /.well-known/security.txt per RFC 9116.

Change log

  • 2026-04-17 — Launch readiness audit closed these gaps: row level security added to api_keys and moderation_logs; explicit policies added to violations; Stripe webhook deduplication via stripe_session_id unique index; atomic spending-cap enforcement; security pipeline failing closed on infra outage; DOMPurify sanitization of Excel/Word preview HTML.
Last updated: April 17, 2026.