Security
Last updated: September 2026
COI Tracker and its VendorReady product line store sensitive vendor insurance data. This page documents how we protect it. Plain English — no marketing filler, and nothing listed here that the code does not do.
Authentication
- Magic-link only. No passwords to phish, leak, or reuse. Sign-in links expire in one hour and are single-use, and are bound to the browser that requested them.
- Sessions live in SameSite cookies scoped to
coitracker.co, refreshed server-side. Our own browser client reads them, so they are not hidden from JavaScript; protection against script injection comes from the Content-Security-Policy below, React’s output escaping, and short token lifetimes.
Data isolation
- Every row in the database is scoped to an owning user. Postgres Row-Level Security enforces this at the database layer — not just in application code — for both the COI Tracker and VendorReady tables.
- File uploads live in private Supabase Storage buckets. Downloads use signed URLs valid for 60 seconds; nobody can browse a bucket.
- The service-role key — which can bypass RLS — is never shipped to the browser. Server code uses it in the daily crons, the Stripe and email webhooks, the public reader’s rate limiter, the vendor upload portal, free-tool lead capture and account deletion. Each of those paths is scoped by a verified session, a signed webhook, or a single-purpose token — never by client input.
Transport and storage encryption
- TLS 1.2+ everywhere, enforced by HSTS with
max-age=63072000; includeSubDomains; preload. - Data at rest is encrypted by our infrastructure providers (Supabase on AWS, Vercel on AWS).
Browser hardening
- A Content-Security-Policy restricts scripts, connections, frames and form targets to an explicit allow-list, forbids plugins and framing, and upgrades insecure requests. It does not yet use per-request nonces, so inline scripts remain permitted; a nonce-based policy is planned once the cached marketing pages move to dynamic rendering.
- X-Frame-Options: DENY — the app cannot be iframed for clickjacking.
- Referrer-Policy: strict-origin-when-cross-origin.
- Permissions-Policy disables camera, microphone, geolocation.
The COI reader
- The public reader holds an uploaded PDF in memory for one request, reads it with on-server engines only, returns the result, and stores nothing — no file, no extracted values, no log of the contents.
- Uploads are capped at 15 MB, checked for a real PDF signature, and rate-limited per client at the application layer and at the edge.
- Signed-in reads keep an extraction record (engine, model version and the extracted values with their source positions) inside the account that ran them. See the Privacy Policy for what leaves our servers and when.
Payments
We never see or store your card. All payment information is handled by Stripe, which is PCI DSS Level 1 certified. COI Tracker stores only the Stripe customer ID and subscription status returned by signature-verified webhook events.
- Reminder and vendor-request emails are sent through Resend on a domain with SPF, DKIM, and DMARC records aligned.
- Every reminder carries an idempotency key and a durable delivery record, so a retry can never send the same reminder twice.
- Replies to vendor-request emails go to your address, not ours — we are a conduit, not a party.
Subprocessors
Supabase (database, storage, authentication), Vercel (hosting and request logs), Stripe (payments), Resend (transactional email), Sentry (error monitoring), PostHog (product analytics — no document contents), and Anthropic (model-assisted reading on the signed-in VendorReady reader only, when on-server engines cannot read a PDF; opt-out by request).
Secrets and keys
- All secrets live in the hosting provider’s encrypted env store.
- No secret is committed to source control.
- Database credentials and service-role keys are rotated on any suspected exposure and at least annually.
Monitoring
- The daily reminder cron pings an external heartbeat monitor; a missed run alerts us.
- Server errors, bounced reminder emails and Stripe webhook failures are captured and alerted on in real time.
Vulnerability reporting
Please email security@coitracker.co with details. We will acknowledge within two business days and keep you informed until the issue is resolved. We do not run a bounty program; if you would like recognition, we credit reporters by name in the fix’s release note.
Incident response
In the event of a confirmed data breach affecting your data, we will notify you by email within 72 hours of confirmation with scope and mitigation steps. You can reach us any time at security@coitracker.co.
Data deletion
Delete your account from the dashboard any time. Deletion runs immediately: your files are removed from storage, active subscriptions are cancelled, and your records are deleted, except for the limited billing records we are required to retain for tax and accounting purposes.