Starting posture of LegacyVault. This document is updated every quarter and any time the threat model materially changes.
| Threat | Impact | Primary control |
|---|---|---|
| Credential stuffing → account takeover | High | MFA enforced; WebAuthn for admins |
| Insider abuse by platform staff | Critical | Per-tenant CMKs, JIT access, full audit, dual-control on prod |
| SQL injection / ORM bypass | High | Prisma parameterized queries; no raw input concat |
| SSRF from document-fetch workers | Med | Allowlist + network egress policy |
| Vendor breach (auth, email, observability) | Med | Minimal PII in third parties; key rotation plan |
| Stolen laptop / lost device | Med | Short JWTs; session revoke on suspicious login |
| Data exfil via legitimate user session | High | Download watermarks, rate limits, anomaly alerts |
- Auth: bearer-token JWT on every non-public route. No password storage. MFA delegated to provider (WorkOS / Clerk).
- Authorization:
@Roles(...)guard on every handler; principle of least privilege. Unauthenticated handlers must explicitly use@Public(). - Field encryption: AES-256-GCM with a 32-byte key, versioned ciphertext
format, integrity via GCM auth tag. See
field-crypto.service.ts. - At-rest encryption: RDS + S3 with KMS CMKs; S3 bucket policy denies non-TLS and public access.
- Audit: append-only log with DB-level REVOKE + trigger; every sensitive action annotated.
- Logging: Pino redact list includes
authorization,cookie,*.password,*.ssn,*.sin,*.govId,*.accountNumber. - Rate limiting: per-IP throttling via
@nestjs/throttler. - Transport: HSTS, TLS 1.3, Helmet security headers.
- CORS: explicit origin allowlist, credentials allowed only from known apps.
- Supply chain:
npm auditin CI (fails on high), Trivy SAST, CodeQL, CODEOWNERS gate on security-sensitive paths.
- WorkOS JWKS verification swap-in (Session 2)
- KMS
GenerateDataKeyenvelope encryption path for field crypto (Session 4) - Postgres Row-Level-Security policies for all tenant-scoped tables (Session 5)
- Pen test before B2B launch (scheduled before Phase-2 GA)
- HackerOne or Bugcrowd program (after SOC 2 Type I)
No secrets live in the repo. Local dev uses a .env generated by
scripts/bootstrap.sh (openssl random). Production uses AWS Secrets Manager
with resource policies scoped to individual task IAM roles.
Any secret discovered in a commit is a P0 incident — rotate immediately, force-push a rewrite of the branch, and open an incident ticket per the incident-response runbook.
Email security@legacyvault.app. PGP key fingerprint published at /.well-known/security.txt
(to be created at domain cutover). We commit to acknowledging within 24h.