Security Model

Security is layers, not a checkbox

Every SaaS says they're "enterprise-grade security." Most of them mean "we use HTTPS."

Here's what we actually built, with specifics:

Layer 1: Edge protection (Cloudflare)

Before your request even hits our code:

  • DDoS mitigation — Cloudflare blocks 182 billion threats/day. Your attack is probably not novel.
  • Bot detection — Challenge Score checks if you're human (Turnstile)
  • IP reputation — Known bad IPs blocked automatically
  • Rate limiting (L7) — 1000 requests/min per IP before we even see the request

Cost to us: $0 (included in Workers)
Attacks blocked: ~90% never reach our code

Layer 2: API key validation

Every request must include: Authorization: Bearer YOUR_API_KEY

// What we check (10-30ms):
1. Is key present? (instant)
2. Is key format valid? (regex, instant)
3. Lookup in Redis cache (hit: 5ms, miss: 20ms)
4. If miss → Lookup in Supabase (20-50ms)
5. Is key active? Not revoked? Not expired?
6. Load user tier (free/pro/enterprise)
7. Load rate limits for this tier
8. Cache result for 5 minutes

If any check fails → 401 Unauthorized (immediate)
No request reaches your code without valid auth

API keys are:

  • Prefixedox_... (you can tell test vs prod keys apart)
  • 32+ characterscrypto.randomBytes(32) (unguessable)
  • Hashed in database — We store bcrypt hash, not plaintext. If our DB leaks, your keys don't.
  • Revocable instantly — Delete from dashboard, takes effect in <5min (cache TTL)

Layer 3: Rate limiting (multi-tier)

We check limits at 3 different layers. Most attacks get blocked at the fastest layer.

Redis Pipeline (186ms) — High-Performance Check
Single Redis round-trip for all checks (Mega-Pipeline)
Limits (per hour):
  • Free: 50 requests/hour
  • Pro: 1,000 requests/hour
  • Enterprise: Custom requests/hour
Why: Batched operations reduce latency by 75% vs sequential checks
Example: User making 60 req/hour on Free tier → Blocked efficiently
Database Check (Async) — Daily/Monthly totals
Supabase query (cached)
Limits (per month):
  • Free: 1,000 requests/month
  • Pro: 50,000 requests/month
  • Enterprise: Custom
Why: Accurate billing, can't be bypassed by clearing cache
Example: User hits 1,000/1,000 on Free tier → Blocked

Why 2 layers? Efficiency + Persistence. Redis handles high-speed limiting, DB handles billing/monthly quotas.

Real story: During testing, someone scripted 500 fake accounts. Redis caught 99% of requests.Zero requests hit our actual code.

Layer 5: Quota enforcement

Every account has hard limits based on tier:

Free Tier
1,000 requests/month
1 API keys
10 files/batch
Pro Tier
50,000 requests/month
10 API keys
100 files/batch
Enterprise
Custom
Custom API keys
Custom files/batch

When you hit a limit:

  • 50% usage — Email warning ("you're at 500/1,000 requests")
  • 80% usage — Email urgent warning + dashboard banner
  • 100% usage — 403 Forbidden with upgrade link (no surprise charges, just blocked)

We never charge overage fees. We block the request and tell you to upgrade. Clean, honest, no surprise $500 bills.

Layer 6: Credential handling (zero-trust)

We don't store your storage provider credentials. This is intentional.

You pass R2/Vercel/Supabase keys in each request body:
→ We use them to generate signed URLs (crypto operation)
→ We discard them immediately (not stored, not logged, not cached)
→ If our database is breached, your credentials are safe

Tradeoff: More work for you (pass keys in each request) vs zero risk of credential leakage from our side.

We validate format only (length, character set), not actual validity. If your credentials are wrong, R2/Vercel will return 403 when you try to upload. We don't pre-check because that would require storing or testing credentials.

Layer 7: Abuse event logging

Every suspicious action is logged in audit_logs table:

  • Rate limit exceeded
  • Invalid credentials submitted
  • Disposable email detected
  • Quota exceeded
  • Verification spam (clicking "verify" 100× in 1 minute)
  • Domain creation spam

Automatic actions:

  • 10 abuse events → Account flagged (manual review)
  • 50 abuse events → Account suspended (automatic)
  • 100+ abuse events → IP banned (escalated to Cloudflare)

We log context: IP address, user agent, timestamp, request body (sanitized). If you appeal a ban, we have receipts.

Layer 8: Signed URLs (limited lifetime)

Every upload/download URL we generate expires:

  • Default: 1 hour (3600 seconds)
  • Min: 1 minute (60 seconds)
  • Max: 7 days (604800 seconds) — R2/S3 limit, not ours

After expiry, the URL returns 403 Forbidden. Can't be replayed, can't be shared indefinitely.

For longer-lived access, use JWT tokens (Pro tier). Tokens are revocable, URLs are not (once signed, valid until expiry).

Layer 9: Transport security

Everything uses HTTPS (TLS 1.3):
→ Your app → Our API (HTTPS)
→ Our API → Supabase (HTTPS)
→ Our API → Redis (TLS)
→ Your browser → R2/Vercel/Supabase (HTTPS)

API keys must be in Authorization header, never in URL query params (prevents logging).

Cloudflare provides:

  • Free SSL certificates (Let's Encrypt, auto-renewed)
  • TLS 1.3 (latest, fastest)
  • HTTP/3 (QUIC) — Faster than HTTP/2, especially on mobile
  • HSTS preload — Force HTTPS, no downgrade attacks

What we DON'T do (important)

  • We don't encrypt your files
    They live in your R2/Vercel account. If you want encryption, enable it there (R2 supports it).
  • We don't scan files for malware
    We never see your files (they upload directly). If you need virus scanning, use Cloudflare Images or a separate service.
  • We don't promise 100% uptime
    Target: 99.9% (8.7 hours downtime/year). Enterprise gets 99.95% SLA. If Cloudflare goes down, we go down with it.
  • We don't prevent you from uploading bad content
    You're responsible for what you upload. We'll cooperate with DMCA/legal requests, but we're not content police.

Summary: 9 layers, 0 buzzwords

1. Cloudflare DDoS/Bot protection (90% of attacks blocked)
2. API key validation (bcrypt, cached, revocable)
3. Multi-tier rate limiting (Redis Mega-Pipeline → DB)
4. Quota enforcement (no surprise charges, just blocks)
5. Zero credential storage (you pass keys, we discard them)
6. Abuse event logging (auto-suspend)
7. Signed URL expiry (1 hour default, 7 days max)
8. TLS 1.3 everywhere (HTTPS, no exceptions)

This is what "enterprise-grade security" actually means. Not a marketing claim, not a compliance badge.Layers of defense that we built, tested, and use ourselves.