Security overview
Last updated: 2026-05-23.
Safe to Publish handles draft marketing material that may quote clients, employees, or third parties by name. This page describes the technical and organizational controls we apply to keep that data confidential, available, and intact. It is the operative security overview referenced in §4 of our Data Processing Addendum.
Safe to Publish is operated by Zackary Trenholme as an Ontario sole proprietorship; we do not yet hold a SOC 2 Type II report. The controls below are nonetheless implemented in production. We will update this page as our control posture changes.
1. Encryption
- In transit. All HTTPS endpoints are served over TLS 1.3 with HSTS preload. The application itself does not accept plaintext HTTP.
- At rest. The Postgres database is encrypted at rest using AES-256 by the managed-database provider (Supabase). Backups inherit the same encryption.
- Reviewer-call transit. Calls to the Anthropic reviewer model are TLS 1.3 to the Anthropic API endpoint. Drafts are retained by Anthropic for up to 30 days for trust & safety monitoring, then deleted; they are not used to train any model.
2. Authentication and session security
- Authentication is delegated to Clerk. Passwords are stored only by Clerk (never by Safe to Publish), salted and hashed per Clerk's implementation.
- Sessions are short-lived JWTs issued by Clerk and verified on every request via the Clerk middleware.
- Multi-factor authentication, passkeys, and SSO (where the customer has it) are available and configured in your Clerk-backed account settings.
3. Tenant isolation
- Every firm-scoped table has Postgres Row-Level Security enabled with a fail-closed policy: a query that does not establish the caller's firm context sees zero rows and cannot insert, update, or delete a row belonging to another firm.
- The application connects to Postgres as a least-privilege role that is explicitly prevented from bypassing Row-Level Security, so the policies are always enforced. The owner role used for schema migrations is never used at runtime.
- Server actions and route handlers wrap every firm-scoped query in a context helper that establishes the caller's firm inside a transaction and clears it on exit; queries that fail to do so see no data.
- A separate, narrowly-scoped database connection is used only by the small set of flows that must operate before the caller's firm is known — for example, the Stripe webhook's customer-to-firm lookup, invitation-token resolution, and the existing-user-by-identity lookup at sign-in. Call sites are audited and reviewed on every change.
4. Audit log
- Every mutation to a review (create, flag dispositioned, plan changed, subscription event, etc.) appends a row to a tamper-evident audit log scoped to your firm.
- Each row carries a SHA-256 hash chained to the previous row in the firm's audit log. Tampering with any historical row breaks the chain and is detected on export.
- From the Audit page, customers can export the audit-log index for their firm as a CSV — one row per review, with the date, type, title, author, severity counts, and disposition status. From any individual review's page, customers can also export the full audit record for that review — including the draft text as submitted, every raised flag, and each flag's disposition — as PDF or as a machine-readable JSON manifest suitable for handing to an examiner.
5. PII auto-redaction
Before any draft is sent to the reviewer model, the application scans for and substitutes detected Social Security Numbers, email addresses, US phone numbers, and dates of birth with same-length placeholders. The substitutions are reversed when the result is rendered back to you, so flag offsets remain correct. Detected counts and types are recorded on each review row for transparency.
6. Backups and recovery
- The database is backed up daily by Supabase with point-in-time recovery available within the retention window of our managed-DB plan.
- Application code is versioned in a Git repository; deploys are reproducible from any commit.
- Configuration secrets are stored only in Vercel's encrypted environment-variable store and are never written to logs or version control.
7. Logging and monitoring
- Request and error logs are captured by Vercel. Retention depends on the Vercel plan in effect and is not committed to a fixed window here.
- Application errors are forwarded to Sentry. PII is filtered out of error payloads before transmission. Stack traces include source-mapped file references but never request bodies.
- Product-usage events (page-views, feature-usage) are sent to PostHog. Draft text and review results are never sent to PostHog.
8. Vulnerability management
- Dependencies are tracked by GitHub's native dependency graph; security advisories trigger an alert and a same-week patch.
- The application stack (Next.js, Drizzle, Postgres) is updated to the current minor release at least quarterly, and to a current major release at least annually.
- Penetration tests are not yet scheduled; we will publish results when we engage one.
9. Incident response
Confirmed personal-data breaches are notified to affected customers without undue delay and in any event within seventy-two (72) hours of confirming the breach, per §7 of the DPA. Notifications include the nature of the breach, the categories and approximate number of data subjects and records affected, the likely consequences, and the measures we have taken or propose to take, to the extent that information is then known.
10. Reporting a vulnerability
If you believe you have found a security vulnerability in Safe to Publish, please email support@safetopublish.com with a description and steps to reproduce. We will acknowledge within 72 hours. We do not currently offer a paid bug bounty.
Questions or a customer security questionnaire? support@safetopublish.com.