Security overview

Last reviewed 2026-04-29

This page describes the security controls actually in place today. Items we have committed to but not yet implemented are listed separately at the bottom under “Commitments and roadmap” — we don’t mix the two.

Hosting

  • Hosted on Google Cloud Platform (Firebase) and Vercel — both SOC 2 Type II attested. Google additionally holds ISO 27001/17/18/701, PCI DSS Level 1, HIPAA, and FedRAMP High. We rely on these inherited controls for at-rest encryption (AES-256 by the platform) and physical security.
  • Primary region: United States.

Network and headers

  • TLS 1.2+ enforced end-to-end (Vercel platform).
  • HSTS with 2-year max-age and preload (next.config.mjs).
  • Strict Content Security Policy with per-request nonces; X-Frame-Options DENY; X-Content-Type-Options nosniff (middleware.js, next.config.mjs).
  • Server-side outbound HTTP wrapped with an SSRF guard that blocks private CIDRs, link-local, and cloud metadata IPs (lib/net/safeFetch.js; CI grep-gate via scripts/audit-unsafe-fetch.js).

Identity and access

  • Passwordless magic-link signin and OAuth (Google, LinkedIn, Facebook).
  • Multi-factor authentication available; mandatory for administrators.
  • Role-based access control with distinct admin/user roles.
  • CSRF protection on auth endpoints (NextAuth).

Data store

  • Firestore Security Rules with user-scoped reads and writes; documents not explicitly allowed are denied. Rule changes go through PR review.
  • Backups: Firestore Point-in-Time Recovery is enabled by the platform; we depend on Google Cloud’s default backup posture for the project.

Audit log

  • Authentication and session-management endpoints (sign-in, MFA enroll/verify/disable, account export, AI consent record) write to an append-only auditLog collection via lib/audit/log.js.
  • Coverage is not universal across the API surface; expanding coverage is a roadmap item below.

Application security

  • Output sanitization for rendered user-provided HTML (lib/security/sanitizeRichText.js, utils/sanitizeHtml.js).
  • Rate limiting on selected high-risk endpoints (signup, writer/generate, writer/revise, AI feedback) via utils/rateLimiter.js. Coverage is not universal across the API surface.
  • Schema validation (Zod) is in place on a small set of newer endpoints; legacy endpoints validate ad-hoc. We do not currently claim universal schema validation.
  • Field-level AES-256-GCM encryption (lib/crypto/fieldEncrypt.js) for high-sensitivity fields: MFA TOTP secrets (lib/mfa/mfaStore.js) and LinkedIn OAuth session cookies (utils/server-utils/linkedinCookieCrypto.js). Other Restricted-class fields are not yet field-encrypted; broadening coverage is on the roadmap.

Dependency and code security (CI)

  • Dependabot for dependency updates (.github/dependabot.yml).
  • Semgrep SAST and CodeQL run on every PR (.github/workflows/security.yml).
  • SBOM generated per release.
  • Custom audit scripts: scripts/audit-unsafe-fetch.js, scripts/verify-ai-zdr.js, scripts/audit-dpa-register.js, scripts/audit-compliance-claims.js.

Error monitoring

  • Sentry for application errors and performance.
  • Note: our current Sentry configuration sends default PII (sendDefaultPii: true) to capture useful debugging context. Tightening this to scrub PII at ingest is on the roadmap below.

AI safety

  • Per-request flags minimize provider storage where supported (store: false on OpenAI, redact=true on Deepgram). We have not signed Zero Data Retention amendments; standard provider retention applies (for OpenAI, up to 30 days for abuse monitoring).
  • We rely on each AI provider’s standard API terms for the no-training default.
  • OpenAI Moderation runs on AI outputs (blocks hate, violence, self-harm, sexual/minors).
  • Prompt-injection / jailbreak detection in lib/ai/safetyGuard.js.
  • AI calls routed through lib/ai/callWithAudit.js log only metadata (model, endpoint, token counts, timing) — never prompt or completion content. Coverage is partial: only some AI call sites currently use the wrapper.
  • See AI disclosure for the full picture, including which features may auto-trigger AI calls in the background.

Compliance posture

  • HIPAA: N/A — PHI is prohibited by our Terms.
  • PCI DSS: SAQ-A scope; Stripe handles all card capture.
  • GDPR / UK GDPR: 2021 EU SCCs and the UK IDTA where required; relies on sub-processor agreements (see Sub-processors).
  • CCPA / CPRA: service-provider posture.

Commitments and roadmap

The following are documented as program commitments. Where evidence of execution does not yet exist in the repository, we describe them as such rather than asserting them as ongoing practice.

  • Quarterly access reviews — documented in docs/compliance/internal-audit.md; first review pending.
  • Annual full + semi-annual partial restore drills — documented in docs/compliance/BCP.md; first drill pending.
  • Annual AI bias evaluation across demographic name variations — methodology in docs/compliance/ai-bias-evaluation.md; first evaluation pending.
  • 72-hour regulator notification SLA for qualifying breaches — documented in docs/compliance/breach-notification.md.
  • Universal audit-log coverage on mutating API routes — currently partial (~8/367 routes).
  • Universal schema validation (Zod) on API routes — currently partial (~4/367 routes).
  • Tighten Sentry to scrub PII at ingest (sendDefaultPii: false + custom beforeSend stripping).
  • Broader field-level encryption coverage (currently used for MFA secrets and LinkedIn OAuth cookies; extend to other Restricted-class fields per docs/compliance/data-classification.md).
  • Wrap remaining direct OpenAI call sites in lib/ai/callWithAudit.js for universal AI audit-log coverage.

Further reading

showUpgradeModal: false, modalType: migration, planName: