Security

Posture, controls, threat model, and disclosure process.

Posture summary

ControlImplementation
TransportTLS 1.3 everywhere
Key storagePeppered SHA-256; pepper in Cloudflare Secrets Store, never in D1 or logs
Key formatck_live_<26-char Crockford base32>, 130-bit entropy
Auth timing80 ms uniform floor across all outcomes
Auth envelopeUniform UNAUTHORIZED; real reason in audit_log only
Rate limit (L1)Per-IP, Cloudflare Workers Rate Limiting, 60 / 60s, fails closed
Rate limit (L2)Per-key, D1 sliding window, 1000 / 60s, keyed on 8-char prefix
CORSPer-org allowed_origins + env-level global allowlist for preflight
Body caps1 MB single / 5 MB batch / 100 interactions per batch
Retentioninteractions 24 months, rate_limits 2 hours, audit_log + alerts 90 days
Tenancy isolationEvery row scoped to org_id; router-enforced, not just query-enforced
Supply chainSBOM generated per release (CycloneDX); gitleaks pre-commit

Data at rest

Data in transit

Threat model highlights

OWASP API Top 10 (2023) mapping

Full mapping in the repo at docs/trust/owasp-api-top-10.md. Summary: all 10 categories are either controlled-for or not applicable to the API surface.

Responsible disclosure

[email protected]. Triage within 48 hours, critical fix within 14 days. Safe-harbor clause for good-faith research. See SECURITY.md in the repo for scope and out-of-scope categories.

Next step