Application & edge security
Every request to Fanzava — from a participant browser, an admin dashboard, a mobile app, or a third-party API client — passes through a single Cloudflare Worker that enforces the platform’s security boundary. The Worker is the application’s enforcement point for authentication, authorisation, input validation, rate limiting, and response hardening.
Edge Worker as security boundary
Section titled “Edge Worker as security boundary”Fanzava runs on Cloudflare Workers at the edge. There is no separate API gateway, no separate auth proxy, no separate WAF appliance — the same Worker that routes the request also enforces the security checks below. This concentrates the security surface into one auditable codebase rather than spreading it across multiple coordinating systems.
For every request, the Worker:
- Verifies the request passes Cloudflare WAF (which executes ahead of the Worker)
- Validates the authentication token (Better Auth for default flows, WorkOS for Enterprise SSO)
- Checks rate limits relevant to the endpoint
- Validates the input against the endpoint’s Zod schema
- Checks the user’s hub membership and role for authorisation
- Executes the handler
- Applies output headers (CSP, security headers) before returning
If any step fails, the request is rejected before reaching the application layer. There is no scenario in which an authenticated handler runs without all of these checks having passed.
Content Security Policy
Section titled “Content Security Policy”A strict Content Security Policy is enforced on all HTML responses. Per-request nonces are generated for inline scripts and styles, rendering injected content unable to execute even if it makes it into the DOM.
| Directive | Value (summary) |
|---|---|
default-src | 'self' |
script-src | 'self' 'nonce-{generated}' https://challenges.cloudflare.com |
style-src | 'self' 'nonce-{generated}' |
img-src | 'self' data: https: (permits hub branding and avatars from any HTTPS host) |
font-src | 'self' https://fonts.gstatic.com |
connect-src | 'self' https://*.fanzava.com |
frame-src | 'none' |
frame-ancestors | 'none' |
object-src | 'none' |
base-uri | 'self' |
form-action | 'self' |
upgrade-insecure-requests | (set) |
Per-request nonces are unique to each response and never reused. CSP violations are reported to a dedicated endpoint and reviewed as part of standard security operations.
HTTP security headers
Section titled “HTTP security headers”In addition to CSP, the following headers are set on every response:
| Header | Value |
|---|---|
Strict-Transport-Security | max-age=31536000; includeSubDomains; preload |
X-Content-Type-Options | nosniff |
X-Frame-Options | DENY |
Referrer-Policy | strict-origin-when-cross-origin |
Permissions-Policy | geolocation=(), microphone=(), camera=(), payment=() |
Cross-Origin-Opener-Policy | same-origin |
Cross-Origin-Resource-Policy | same-site |
Cross-Origin-Embed-Policy | require-corp (on sensitive pages) |
Fanzava participates in the HSTS preload list, so browsers refuse insecure connections to fanzava.com and its subdomains even on first contact.
Web Application Firewall
Section titled “Web Application Firewall”Cloudflare’s managed WAF runs ahead of the Worker and blocks known attack patterns before they reach application logic. Active rule families:
- OWASP Core Rule Set — SQL injection, XSS, command injection, request smuggling, protocol violations
- Cloudflare Managed Rules — emerging exploits, known-bad bots, credential-stuffing patterns
- Custom rules — Fanzava-specific protections (block requests to internal-only paths, enforce tenant context on subdomain requests)
WAF events are logged and reviewed. Customers do not configure the WAF directly — Fanzava manages it centrally to maintain a consistent baseline across all hubs.
Rate limiting
Section titled “Rate limiting”Rate limits are enforced at the Worker layer, per identity, per endpoint, with separate buckets for authenticated and anonymous traffic:
| Endpoint family | Anonymous limit | Authenticated limit |
|---|---|---|
| Authentication (sign-in, magic link request) | 10 / minute per IP | n/a |
| Password reset | 3 / hour per IP+email | n/a |
| MFA challenges | 5 / 15 minutes per user | 5 / 15 minutes per user |
| Tip submission | n/a | 60 / minute per user |
| Leaderboard read | 30 / minute per IP | 120 / minute per user |
| Admin write operations | n/a | 100 / minute per admin |
| Webhook delivery | 100 / second per hub | n/a |
| Public API (Pro / Enterprise) | n/a | per token, configured per integration |
Excess requests receive 429 Too Many Requests with the Retry-After header set. Rate-limit events for authentication and password reset are recorded in the Audit log.
Input validation
Section titled “Input validation”All API endpoints validate their inputs against a Zod schema defined alongside the route handler. The schema is the contract — no input reaches the handler without conforming to it.
Validation covers:
- Type correctness (string, number, boolean, enum)
- Format constraints (email, UUID, ISO date, URL)
- Length and range constraints
- Cross-field invariants (e.g.
end_datemust be afterstart_date) - Whitelist enforcement (only known sports IDs, only known tier IDs)
If validation fails, the request is rejected with 400 Bad Request and a structured error describing which field failed. The handler is never invoked.
CORS policy
Section titled “CORS policy”The Fanzava API enforces a strict CORS policy:
- API requests from Fanzava-owned domains (
*.fanzava.com, custom domains configured for hubs) are permitted with credentials - API requests from other origins are permitted only for explicitly public endpoints (unauthenticated leaderboard reads where the hub has chosen public sharing)
- Pre-flight
OPTIONSrequests are handled by the Worker without invoking the handler - All cross-origin responses include
Vary: Originto prevent cache poisoning
Zero-trust authorisation
Section titled “Zero-trust authorisation”Authentication and authorisation are evaluated on every request. There is no “behind the firewall” context — every request runs through the same checks:
- Authentication — the bearer token or session cookie is validated against the auth provider on every request
- Hub membership — the user’s claim of hub membership is verified against their identity record
- Role check — the user’s role within the hub is verified against the endpoint’s required role
- Group membership (where applicable) — for group-scoped endpoints, group membership is verified before the query executes
The Worker does not trust any client-supplied identity or role claim. All authorisation is derived from server-side data. See Tenant isolation for how this enforces hub and group scoping.
DDoS protection
Section titled “DDoS protection”Cloudflare’s network-level DDoS protection sits ahead of the Worker. Volumetric attacks are absorbed and filtered at Cloudflare’s edge, never reaching the application. Layer-7 DDoS mitigation is automatic for HTTP floods, and the WAF blocks application-layer abuse patterns.
For Enterprise hubs facing targeted attack risk, additional Cloudflare protections (Advanced Rate Limiting, Bot Management, custom WAF rules) can be applied per-hub. Contact your account manager.
Vulnerability disclosure
Section titled “Vulnerability disclosure”Report security issues to security@fanzava.com. Fanzava acknowledges reports within 24 hours and provides status updates every 48 hours until resolution. See Compliance posture for full disclosure policy.