Security

What we
actually do.

Everything below is either something this codebase does — with the file that does it named beside it — or a platform fact attributed to the provider who supplies it. Nothing here is planned, and nothing is a certification we do not hold.

In our code

  • Sensitive fields are encrypted before they reach the database
    AES-256-GCM, applied in the application layer. Every value is stored with its own random IV and an authentication tag, so a modified ciphertext fails to decrypt rather than returning altered data.
    lib/crypto.ts
  • Six categories of field are covered
    Contact cell-phone numbers, calendar addresses, connected-mailbox OAuth tokens, bank fields on invoices, and Google Analytics tokens — each with its own key, so one compromised key does not read the others.
    lib/crypto.ts
  • Mailbox tokens are never stored in plaintext
    When you connect Gmail or Microsoft for sending, the refresh and access tokens are encrypted before storage and decrypted only to make the send. A refreshed token is re-encrypted before it is written back.
    lib/mailbox/refresh.ts
  • Tenant isolation is enforced by the database, not the application
    Row-Level Security policies decide what your workspace can read, so a bug in application code cannot return another workspace's rows. Eighteen test files exercise those policies directly against the database.
    tests/rls/
  • Card details never reach our servers
    Payment happens in Stripe Checkout and the Stripe Billing Portal. Pitcher never receives, transmits or stores a card number, expiry or CVC — there is no code here that could.
    lib/billing/checkout.ts
  • HTTPS is required, not merely offered
    Strict-Transport-Security is sent on every response with a one-year max-age and includeSubDomains, so a browser that has seen the site once refuses to speak to it over HTTP afterwards.
    next.config.ts
  • The app cannot be framed
    X-Frame-Options and a Content-Security-Policy frame-ancestors directive both deny embedding, which closes clickjacking against the authenticated product.
    next.config.ts
  • Sign-in is delegated, so we hold no passwords
    Authentication runs through Supabase Auth, including Google sign-in. Pitcher stores no password hashes because it is never given a password.
    app/auth/actions.ts

From our platform

Two things we rely on rather than implement. They are real, and they are not ours to claim credit for — so they are attributed, and you can read each provider's own account of them.

  • Encryption at rest
    The database is hosted on Supabase, which encrypts stored data at rest. The field-level encryption above sits on top of that, so the most sensitive values are encrypted twice by different systems with different keys.
    supabase.com/security
  • TLS in transit
    The application is served by Vercel, which terminates TLS on every request. Our own HSTS header is what stops a browser from ever trying plain HTTP in the first place.
    vercel.com/security

What we do not have

Pitcher is not SOC 2 certified. If your client runs a vendor security review that requires a SOC 2 report, we cannot supply one today. We say so here for the same reason our comparison pages record it as an advantage a competitor has over us: a security page that skipped the subject would be answering a different question than the one you asked.

We also publish no penetration-test report and operate no formal vulnerability disclosure programme. If you find something, email info@prpitcher.com and it will reach a person — see Support for how quickly.