← Trust CenterSecurity Architecture
Each control below cites the file (or files) that implement it. If procurement asks for code-level evidence, this is the reference.
See also: the more accessible /security marketing page.
Encryption at rest
OAuth tokens stored in `oauth_tokens.access_token` / `refresh_token` are AES-256-GCM encrypted with a per-row 96-bit random IV. Wire format `v2:<iv>:<tag>:<ct>` (was `v1:` prior to W1-A7 key rotation). Plaintext is never logged.
- lib/integrations/oauth/crypto.ts
- lib/auth/sso/index.ts
- lib/auth/2fa/index.ts
Encryption key rotation
Dual-key reader supports v1 → v2 rotation without downtime. Re-encrypt is online via /api/cron/key-rotation-reencrypt, gated by KEY_ROTATION_IN_PROGRESS. Progress persists in `key_rotation_jobs` so a crash resumes from `last_id`. Operator playbook: docs/runbooks/key-rotation.md.
- lib/integrations/oauth/crypto.ts (reencryptToV2)
- app/api/cron/key-rotation-reencrypt/route.ts
- supabase/migrations/20260630_key_rotation_jobs.sql
- docs/runbooks/key-rotation.md
Encryption in transit
All public endpoints terminate TLS 1.2+ at the Vercel edge with HSTS preload (max-age=63072000; includeSubDomains; preload). Internal hops use the Supabase/PostgreSQL TLS connection. HSTS header set in next.config.ts headers().
- next.config.ts (HSTS, X-Frame-Options, Referrer-Policy)
- .well-known/security-headers.json
Authentication
Supabase Auth (email + OAuth + SSO). Optional 2FA via TOTP (RFC 6238) with backup codes (lib/auth/2fa). Enterprise SAML/OIDC SSO via @node-saml/node-saml with XSW protection. SCIM 2.0 endpoint for provisioning.
- lib/auth/2fa/
- lib/auth/sso/
- app/api/auth/sso/[provider]/
- app/api/scim/
Authorisation (RBAC)
Six roles (owner, admin, editor, billing, viewer, integration) × four actions (create / read / update / delete / manage) × twelve resources. Enforcement is wrapped at the route layer via `guardRouteWithContext` so every API endpoint goes through the same check.
- lib/auth/rbac.ts
- lib/api/rbac-guard.ts
Tenant isolation
Workspace-scoped rows on every multi-tenant table. Two defence layers: route-layer `workspace_id` enforcement (lib/auth/workspace.ts) AND Postgres Row-Level-Security policies on 56+ tables (supabase/migrations/*). RLS is applied via the anon key; service-role usage is allowlisted (lib/db/service-role-allowlist.ts).
- lib/auth/workspace.ts
- supabase/migrations/*_rls.sql
- lib/db/service-role-guard.ts
Audit log + tamper-evident hash chain
Every mutating API call lands in `audit_log` (action, resource, workspaceId, userId, ip_address, user_agent, prev_hash, entry_hash). The hash-chain (SHA-256(prev_hash ∥ workspace ∥ user ∥ action ∥ resource ∥ ts)) makes silent in-place edits detectable. Coverage is now ~100% via the W1-A7 default-hook in guardRouteWithContext.
- lib/audit/log.ts
- lib/api/rbac-guard.ts (emitApiAudit)
- supabase/migrations/20260623_audit_log_tamper_protection.sql
Anomaly detection
Five detectors run against the audit log: mass-delete, privilege-escalation, geographic anomaly, brute-force (login failures by IP), off-hours-admin. Detectors emit alerts via the standard logger and create entries in `security_events` for the dashboard.
- lib/security/anomaly/
- lib/security/detectors.ts
Rate limiting + WAF
Per-IP and per-workspace token-bucket limits enforced in lib/security/rate-limiter.ts. WAF + DDoS protection via Cloudflare in front of Vercel. Cron-route auth via shared lib/cron/auth helper.
- lib/security/rate-limiter.ts
- lib/cron/auth.ts
Dependency management
GitHub Dependabot configured for security + version updates. Security advisories tracked on https://github.com/CodaiqHasso/ORCONIC/security/advisories. Lockfile (`package-lock.json`) committed; CI fails on unaudited installs.
- .github/dependabot.yml
- package-lock.json
Observability
OpenTelemetry instrumentation (lib/observability/otel-*) with OTLP export. Sentry for error tracking (sentry.*.config.ts). Langfuse for AI request tracing. Structured logs include requestId, userId, workspaceId, route.
- lib/observability/
- sentry.server.config.ts
- instrumentation.ts
Data retention + erasure
GDPR Art. 17 erasure via app/api/gdpr/erase. Workspace-level retention configurable under workspaces.metadata.audit_retention (default 90d) and enforced by app/api/cron/audit-prune. Legal-hold flag exempts a workspace from automatic pruning.
- lib/audit/retention.ts
- app/api/cron/audit-prune/route.ts
- app/api/gdpr/
Backups + DR
Supabase daily snapshots + 7-day point-in-time recovery on the production database. Restore runbook at docs/runbooks/db-restore.md. RPO ≤ 5 min for prod-tier workspaces.
- docs/runbooks/db-restore.md
- docs/runbooks/disaster-recovery.md