The EloWard backend is designed with a security-first architecture. This document summarizes what data is handled, where it lives, and the controls we apply.
- D1 Database (see
users.sql,subscriptions.sql,lol_ranks.sql,bot_channels.sql,channel_viewers_daily.sql,stripe_events.sql):users: Twitch profile data and app metrics (no OAuth tokens stored)subscriptions: Stripe metadata and activation flags (no card data)lol_ranks: League of Legends rank data keyed by Riot PUUID with peak rank trackingtwitch_bot_users: Bot configuration per channel (minimal PII)channel_viewers_daily: Viewer qualification tracking (PUUID + channel + date)stripe_events: Webhook event idempotency tracking
- R2 (via CDN worker): Rank badge images only
- KV (Bot worker): EloWardBot tokens (moderation scopes) and minimal state
- Redis (Bot worker): Instant config propagation via pub/sub (no persistent data)
- Riot/Twitch tokens are exchanged server-side and not returned to clients except when strictly necessary for redirects.
- Workers never persist user Riot/Twitch access tokens in D1.
- Bot tokens (for EloWardBot) are stored in KV and refreshed server-side with automatic refresh.
- Stripe webhooks are verified using the official library and your
WEBHOOK_SECRET. - HMAC-secured bot communication uses shared secrets with timestamp validation (±60s window).
- Write endpoints (e.g., rank and user upserts) require
X-Internal-Authwith a secret (*_WRITE_KEY/INTERNAL_WRITE_KEY). - Database workers only accept writes from authorized auth workers via service bindings + internal header.
- HMAC-signed requests for bot communication with timestamp validation (±60s window).
- Redis pub/sub messages are authenticated via API tokens.
- HTTPS-only endpoints (Cloudflare Workers).
- CORS is restricted to production origins where appropriate; otherwise minimal and explicit.
- No secrets or tokens are logged. Logs include IDs/status codes only.
- Redis connections use TLS with API token authentication.
- HMAC request validation prevents replay attacks with timestamp windows.
- Service bindings are scoped to only what each worker needs (e.g., RiotAuth worker can call Ranks/Users workers; Ranks has direct D1 only).
- API keys (RIOT_API_KEY, Stripe secret) are held in environment variables, not in source.
- Redis access is limited to pub/sub operations only.
- HMAC secrets are worker-specific and not shared across services.
- Viewer tracking data is minimal (PUUID + channel + date only).
If you discover a vulnerability:
- Do not open a public issue.
- Email: unleashai.inquiries@gmail.com
- Include steps to reproduce and impact assessment.
- Please allow reasonable time for a fix before public disclosure.
workers/riotauth/riotauth-worker.ts(Riot OAuth, rank fetch + store, Op.gg scraping)workers/twitchauth/twitchauth-worker.ts(Twitch OAuth, user register)workers/ranks/rank-worker.js(D1 rank storage + reads, user options)workers/users/users-worker.js(D1 user storage + metrics, viewer tracking)workers/stripe/stripe-worker.js(Stripe webhook verification)workers/elowardbot/bot-worker.ts(HMAC validation, Redis pub/sub, KV, token management)workers/cdn/cdn.js(R2 asset serving with path validation)
- We store minimal PII (Twitch profile info) to operate the service.
- No passwords are ever collected; OAuth flows use provider infrastructure.
- Users can disconnect Riot linkage which removes rank data by PUUID.
- Viewer tracking data is anonymized (PUUID only, no usernames).
- Peak rank seeding uses public Op.gg data only.
- Redis pub/sub messages contain no PII, only configuration updates.