// security posture

Security, in detail.

The platform is on Cloudflare's edge, secrets are never in the repo, card data never touches our backend, recordings are encrypted at rest, every money movement is a ledger row. Here's what that means in practice.

01// stack

Built on Cloudflare's edge. No origin server.

The entire platform runs on Cloudflare Workers. There is no long-running server, no SSH access, and no traditional VM to harden or patch. Each request hits a stateless Worker, talks to the managed services below, and returns.

Code deploys are atomic — every push is a new Worker version with a rollback path. Secrets live in Cloudflare Secrets (never the repo) and are injected at runtime.

runtimecloudflare workers · isolate-based
routinghono framework · single api worker
cdncloudflare pages · static frontend
deploywrangler · atomic versions · rollback
02// auth

Magic link only. No passwords.

There is no password to phish or reuse. Sign-in is a single-use magic link emailed via Resend, valid for 15 minutes. Cloudflare Turnstile gates the request to filter bots.

Once verified, a signed JWT is set in an HttpOnly, Secure, SameSite=Lax cookie for 30 days. JavaScript on the page cannot read it. Sign-out revokes the cookie and rotates the session row.

flowemail → magic link → jwt cookie
expiry15-min link · 30-day session
hardeningturnstile · rate-limit 3/10min/email
cookieHttpOnly · Secure · SameSite=Lax
03// payments

Stripe Connect Express. Hitlooper never sees a card number.

All deposits, transfers, refunds, and payouts route through Stripe. Card numbers, CVCs, expiry dates — Hitlooper's backend never receives any of them. PCI compliance is offloaded to Stripe.

Payouts use Stripe Connect Express — each Hitlooper completes Stripe's KYC on their own account. We trigger transfers; they own the bank relationship.

intakestripe checkout · hosted ui
payoutsconnect express · per-account kyc
refundsstripe.refunds.create · idempotent
webhookssignature-verified · stripe_webhook_secret
04// data

Encrypted at rest. Signed access.

Project data lives in Cloudflare D1 (SQLite at the edge) — encrypted at rest by Cloudflare's storage layer. Recordings live in Cloudflare Stream with signed-URL playback; deliverable JSON + NDA copies live in R2 with signed-URL access scoped to each user.

AI inference (Whisper transcription, scoring) runs via Workers AI and the AI Gateway. Audio leaves Stream for transcription and returns — it does not get logged or retained for model training.

databased1 · encrypted at rest
recordingscf stream · signed playback
artifactsr2 · signed urls · scoped per user
ai inferenceworkers ai + ai gateway · no training retention
05// audit + integrity

Every money movement is a ledger row.

Settlement, refund, dispute resolution, and reputation event flows all write append-only rows to dedicated tables (`transactions`, `reputation_events`, `disputes`). Nothing is updated in place. A Stripe transfer that retries uses a unique idempotency key — you cannot get paid twice.

Claim races are arbitrated by a per-project Durable Object so there's no SQLite consistency window during the most contentious moment in the loop. The fallback is a unique constraint that catches anything the DO misses.

ledgertransactions table · append-only
stripeidempotency key per transfer
claim racedurable object · serialised
fallbackunique constraint on claims.project_id
06// nda + ip

NDA at the moment of claim.

Toggle "NDA required" on a project posting and only Hitloopers who have e-signed the platform NDA at least once can claim it. The signed copy is stored in R2, timestamped to the user and the claim.

The default template is mutual, Delaware-governed, two-year term, no IP assignment, no non-compete. The full text and copy/download buttons live at /nda-template.

signinge-sign · timestamped to claim
storager2 · per-user · per-claim
templatemutual nda · delaware · 2-year term
scopeno ip assignment · no non-compete
07// report a vulnerability

Find something? Please tell us.

We don't have a paid bug-bounty program yet. We do have a human inbox. Reach out via the contact form with intent "support" and the subject line will route straight to engineering.

We commit to: acknowledge within 24h on weekdays, fix Critical / High severity within 7 days, public credit in the changelog (with your permission), and won't pursue legal action against good-faith security research.

intakecontact form · intent=support
ack sla24h weekdays
fix slaCritical/High · 7 days
creditchangelog entry · with permission

Security question we didn't cover? Ask.

The contact form has a partnership intent for compliance teams, and a support intent for technical questions. Both go to a human who actually reads them.