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:
- Prefixed —
ox_...(you can tell test vs prod keys apart) - 32+ characters —
crypto.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.
Limits (per hour):
- Free: 50 requests/hour
- Pro: 1,000 requests/hour
- Enterprise: Custom requests/hour
Example: User making 60 req/hour on Free tier → Blocked efficiently
Limits (per month):
- Free: 1,000 requests/month
- Pro: 50,000 requests/month
- Enterprise: Custom
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:
1 API keys
10 files/batch
10 API keys
100 files/batch
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
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.