▸ Annual security review 2026
Self-audit. Public. Honest.
Self-audit against the two most-respected application + organisation security frameworks. Each control is listed below with our current status and supporting evidence. Where we're partial or not-applicable, we say so; we don't claim wins we can't defend.
Reviewed: 28 May 2026 · Frameworks: OWASP ASVS 4.0.3 · CIS Critical Security Controls v8
Pass
24 / 28
86%
Partial
4 / 28
14%
Access Control
CIS v8
CIS-6.5Require MFA for administrative access
TOTP available for every account, encouraged but not yet required. Phase 30+ will enforce for super-admin + billing-changing actions.
Partial
Account Management
CIS v8
CIS-5.1Establish and maintain an inventory of accounts
Per-tenant auth.json + super-admin auth.json + (when Clerk enabled) Clerk Users dashboard. listTenants() in lib/tenant/index.ts enumerates.
Pass
Application Software Security
CIS v8
CIS-16.1Establish a secure application development process
Single-author solo team; every change goes through type-check + lint + plan-mode review before merging. SDLC documented as Phase 30+ when team grows.
Pass
CIS v8
CIS-16.7Use standard hardening configuration templates
Next.js standalone build + Fly.io managed runtime + Docker base image with minimal surface. proxy.ts enforces application-layer hardening.
Pass
Audit Log Management
CIS v8
CIS-8.2Collect audit logs
lib/audit.ts (per-tenant) + lib/superadmin-auth.ts (operator). Both append-only, both timestamped.
Pass
CIS v8
CIS-8.5Collect detailed audit logs for sensitive data access
Key-access audit log built in Phase 29.7 + visible to tenant on /security. Backfill of historical access not retroactive — log starts from Phase 29.7 deployment.
Partial
Authentication
OWASP ASVS
ASVS-2.1.1Passwords are at least 12 characters in length
Argon2id-hashed; password length validation in lib/auth.ts. Sovereign installs only — hosted uses Clerk, which enforces its own policy.
Pass
OWASP ASVS
ASVS-2.1.2Passwords are NOT truncated
Full plaintext passed to argon2Hash; no truncation in lib/auth.ts.
Pass
OWASP ASVS
ASVS-2.4.1Passwords are stored using approved one-way hash function (Argon2id, scrypt, bcrypt, PBKDF2)
Argon2id with OWASP-2024 parameters (memory 65536 KiB, time 3, parallelism 4) in lib/auth.ts:31-36.
Pass
OWASP ASVS
ASVS-2.7.2Out-of-band authenticator (TOTP)
RFC 6238 TOTP available on every account. Optional in v1; will be required for high-risk actions (billing changes, integration changes) in Phase 30+.
Pass
OWASP ASVS
ASVS-2.7.5WebAuthn / passkey
WebAuthn supported via @simplewebauthn (per-tenant rpId). On hosted-with-Clerk installs, Clerk provides passkey UI; on Sovereign, our own /settings/security flow registers them.
Pass
Communications
OWASP ASVS
ASVS-9.1.1TLS 1.2+ enforced
HSTS max-age=63072000 with includeSubDomains + preload directive set in proxy.ts. Verify with `curl -I https://scarifone.com`.
Pass
Configuration
OWASP ASVS
ASVS-14.4.1Verify that every HTTP response contains a Content-Security-Policy header
CSP set on every non-/api response in proxy.ts with explicit allowlist for Stripe, Clerk, Meta Pixel, Gemini, Anthropic, OpenAI, Shopify, Judge.me. Violation reports POST to /api/csp-report.
Pass
OWASP ASVS
ASVS-14.4.3Verify that X-Content-Type-Options: nosniff is set
Set in proxy.ts.
Pass
OWASP ASVS
ASVS-14.4.4Verify a strong Referrer-Policy is set
Referrer-Policy: strict-origin-when-cross-origin set in proxy.ts.
Pass
OWASP ASVS
ASVS-14.4.5Verify that X-Frame-Options is set or CSP frame-ancestors is set
Both set: X-Frame-Options: DENY (SAMEORIGIN for /email-templates/ previews) and CSP frame-ancestors 'none'.
Pass
Cryptography
OWASP ASVS
ASVS-6.2.1All cryptographic modules fail securely
AES-256-GCM via Node crypto in lib/secrets.ts. Tag verification on every decrypt; corrupted ciphertext throws and the caller surfaces a clear error rather than returning plaintext.
Pass
OWASP ASVS
ASVS-6.2.4All cryptographic modules use approved algorithms
AES-256-GCM (NIST FIPS 197), Argon2id (RFC 9106), HMAC-SHA256 (RFC 2104), Ed25519 (RFC 8032 for licence signing). No deprecated algorithms in lib/.
Pass
Data Protection
CIS v8
CIS-3.11Encrypt sensitive data at rest
Tenant secrets (AI keys, integration tokens) envelope-encrypted with AES-256-GCM. See lib/secrets.ts.
Pass
CIS v8
CIS-3.14Log sensitive data access
Per-tenant audit log captures meaningful actions; AI key access has its own logging at /security under each tenant (Phase 29.7). Super-admin actions logged separately at /data/superadmin/audit.log. Not yet sampling-based for read-heavy callsites — Phase 30+.
Partial
Data Recovery
CIS v8
CIS-11.1Establish and maintain a data recovery process
Encrypted nightly backups to S3-compatible storage (R2 / B2 / AWS). Restore documented; self-serve restore UI is Phase 30+.
Pass
Incident Response
CIS v8
CIS-17.1Designate personnel for incident response
Tom (founder, solo). [email protected] forwards to his pager-equivalent. 72h breach-notification commitment published at /trust#breach.
Pass
CIS v8
CIS-17.4Establish and maintain an incident response process
Documented at /trust#breach; postmortems published at /incidents.
Pass
Network Monitoring
CIS v8
CIS-13.1Centralised security event alerting
Application errors surface via Fly logs + Slack webhook. No SIEM yet; not relevant at our current scale but flagged for Phase 30+ as customers grow.
Partial
Session
OWASP ASVS
ASVS-3.2.1Sessions are unique to each individual and cannot be guessed
HMAC-SHA256-signed cookies with per-tenant random secret. 30-day TTL (7-day for super-admin).
Pass
OWASP ASVS
ASVS-3.4.1Cookies have Secure attribute
Set in production via the cookie-set helper in app/api/auth/login/route.ts. Secure conditionally enabled when NODE_ENV=production.
Pass
OWASP ASVS
ASVS-3.4.2Cookies have HttpOnly attribute
HttpOnly always set.
Pass
OWASP ASVS
ASVS-3.4.3Cookies have SameSite attribute
SameSite=Lax always set.
Pass