Security

How we handle your data.

Tapeline is a financial-data product. Trust matters more than features. We'd rather over-explain how the security works than make you guess. If anything below changes, the changelog records it.

Encryption

In transit

Every page and every API call runs over HTTPS with HSTS preload (2-year max-age, includeSubDomains). HTTP requests are 308-redirected to HTTPS by Cloudflare and Fly.io's edge before they reach our application. The HSTS header is verifiable: curl -sI https://tapeline.io | grep -i strict-transport.

At rest

The production database (managed Postgres) is encrypted at rest via AES-256. Daily snapshots are encrypted. Application secrets (API keys, webhook signing keys, JWT signing keys) are stored as Fly.io secrets — encrypted at rest, never in source, never in logs.

Passwords

bcrypt with cost factor 12. We never see your plaintext password — bcrypt-hashed at the moment of signup before the row hits the DB. Password reset uses signed single-use tokens with a 1-hour TTL.

Payment data

We don't store card numbers

All payment processing runs through Stripe — your card details go directly from your browser to Stripe's PCI-DSS Level 1 vault, not through our servers. We store only Stripe's tokenised customer ID and subscription metadata (tier, status, renewal date).

Stripe webhook integrity

Every Stripe webhook event is signature-verified server-side using Stripe's webhook secret. Replay attacks are prevented by an event-ID idempotency check (we log every processed event ID and skip duplicates).

Cancel any time

Cancellation runs through Stripe's customer portal. We never hold subscriptions hostage — one click cancels, no email-back-and-forth, no retention pop-ups.

Account access

Cookie-based sessions

JWT in an HttpOnly + Secure + SameSite=Lax cookie. JavaScript on the page can't read it (mitigates XSS). The cookie is scoped to tapeline.io so it works across the marketing site and the app.

OAuth providers

Google + Microsoft Entra are supported as alternatives to email + password. We receive the standard OIDC profile claims (email, name, sub) and nothing else — no contact list, no calendar, no Drive.

Rate limiting

Auth endpoints (/api/auth/*) are capped at 10 attempts per IP per minute. The general /api/* limit is 120 req/min per IP. Both are enforced in-process before any DB work — brute-force attempts get 429ed cheaply.

Bot + abuse defence

Three layers on signup

(1) Honeypot field — invisible to humans, filled by bots, returns a fake-success that creates no account. (2) Disposable-email block list of ~62 throwaway providers. (3) Cloudflare Turnstile — privacy-preserving CAPTCHA, no third-party tracking.

Cloudflare edge

Bot Fight Mode is enabled at Cloudflare's edge (free tier). Most low-effort scraping attempts are blocked before they reach our origin.

Vulnerability disclosure

Found something?

Email security@tapeline.io with a description and reproduction steps. We acknowledge within 24 hours and target a fix within 7 days for high-severity issues. We don't have a paid bounty programme yet (small team) but we credit researchers who want public credit.

What's in scope

tapeline.io, app.tapeline.io, api.tapeline.io. Authenticated bypasses, IDOR, XSS, SSRF, RCE, sensitive-data exposure, broken auth — all in scope.

What's out of scope

Self-XSS, missing security headers on third-party domains we don't control, social engineering of staff, denial of service via volume. The /api/health endpoint intentionally has no rate limit (it's the Fly health probe target).

Data rights

What we collect

Email, password hash, name (optional), tier, watchlist contents, alert rules, Stripe customer ID, IP address (for rate-limit + audit logs only — not associated to user records). Plus standard server logs (timestamp, path, status code) for 30 days.

What we don't

No browsing history outside Tapeline. No third-party trackers. No advertising pixels. Plausible analytics (when enabled) is cookie-free and doesn't fingerprint.

Export + deletion

Email privacy@tapeline.io with the subject “Data export” or “Account deletion” and we respond within 30 days (UK/EU GDPR + California CCPA timelines). Account deletion is hard-delete, not soft-delete — your row is removed from the production DB and next-day backup rotation removes it from snapshots within 7 days.

Operational

System status

Live at /status — refreshes every 30 seconds. Shows API health, worker tick recency, database reachability, and per-vendor configured-ness. Same data exposed as JSON at api.tapeline.io/api/status for uptime monitors.

Incident response

Backend errors are logged to Fly + (when enabled) Sentry. Client-side React errors ship to /api/log-client-error so they land in the same log stream. Major incidents get an email to subscribers within 24 hours.

Hosting + region

Backend runs on Fly.io (Sydney region). Database is managed Postgres in AWS Sydney. Frontend is on Vercel's global edge network. All infrastructure is multi-zone within the region.

Last verified 2026-05-04. Re-verified quarterly. Spot something out of date? security@tapeline.io.