Skip to content

Zero Trust Architecture

Zero Trust Architecture

The bloqr-backend implements Zero Trust Architecture (ZTA) across every layer of the stack — from the Cloudflare edge to the Angular frontend. This document describes the threat model, architecture, and implementation details.

Core Principle

Never trust, always verify. Every request is verified at every layer regardless of origin — including internal service-to-service calls, queue messages, webhook payloads, and admin operations.

Threat Model

ThreatMitigation
Unauthorized API accessClerk JWT + API key authentication on all write endpoints
Privilege escalation4-tier authorization (Anonymous → Free → Pro → Admin) with least-privilege
CSRF / cross-origin attacksCORS origin allowlist on write/authenticated endpoints
Bot abuseCloudflare Turnstile human verification on compile endpoints
Admin impersonationDual-layer: X-Admin-Key + Cloudflare Access JWT
SQL injection100% parameterized D1 queries via .prepare().bind()
SSRF via proxyRFC 1918 / localhost / metadata IP blocking on /proxy/fetch
XSS via API responsesZod schema validation on all frontend API consumption
Credential theftClerk SDK for auth state — no tokens in localStorage
Rate abuse5-tier rate limiting keyed by authenticated user or IP
Secret leakageWorker Secrets only; CI lint checks for secrets in [vars]
BOLA / IDORResource queries scoped to authContext.userId; validated by API Shield Vulnerability Scanner
Client-side script injection / supply-chain compromiseCSP enforcement via contentSecurityPolicyMiddleware(); violations reported to POST /api/csp-report and persisted to D1; Page Shield script-inventory sync generates ABP block/allow rules — see Page Shield Integration

Architecture Layers

Layer 1: Cloudflare Edge

Before the Worker executes, Cloudflare provides:

  • Turnstile: Human verification on write endpoints (/compile*, /validate, /workflow/*)
  • Cloudflare Access: JWT verification on /admin/* and management routes
  • WAF: API Shield schema validation and bot score thresholds
  • Bot Fight Mode bypass rule: Allows curl/programmatic clients to reach all /api/* paths on api.bloqr.dev (see below)
  • Rate Limiting: Edge-level rate limiting before Worker invocation
  • API Shield Vulnerability Scanner: Stateful BOLA/logic-flaw detection using AI call graphs (beta) — see API Shield Vulnerability Scanner

WAF Bot Fight Mode Bypass Rule

Bot Fight Mode is enabled on api.bloqr.dev to block automated browser scrapers. However, legitimate programmatic clients (curl, SDKs, CI pipelines) that send API keys must be able to reach the API without being challenged. A WAF custom rule configured with Action: Skip → Bot Fight Mode exempts them.

The rule expression must cover all /api/* paths — not just /api/admin/*:

(http.host eq "api.bloqr.dev") and (http.request.uri.path wildcard "/api/*")
FieldValue
Rule nameAllow programmatic clients on API
Expression(http.host eq "api.bloqr.dev") and (http.request.uri.path wildcard "/api/*")
ActionSkip → Bot Fight Mode
Zonebloqr.dev → Security → WAF → Custom rules

⚠️ Common misconfiguration: Scoping the rule to /api/admin/* only will silently block all non-browser clients on every other API endpoint (/api/compile, /api/auth/*, etc.) with a 403 Forbidden and cf-mitigated: challenge response header. If curl requests return 403, check this rule first. See KB-007 for the full diagnosis.

Layer 2: Worker Request Handling

Every request entering worker/worker.ts follows this flow:

Request → CORS preflight check → Authentication → Authorization → Rate Limit → Handler
  1. CORS: handleCorsPreflight() for OPTIONS; getCorsHeaders() on all responses
  2. Auth: authenticateRequestUnified() produces IAuthContext with user, tier, scopes
  3. Auth gate: requireAuth(authContext) blocks anonymous access on protected routes
  4. Rate limit: checkRateLimitTiered() enforces per-tier limits
  5. Security telemetry: AnalyticsService.trackSecurityEvent() on all failures

Layer 3: Data Validation

All trust boundaries use Zod runtime validation:

BoundarySchema
Clerk webhook payloadsClerkWebhookEventSchema
Clerk JWT claimsClerkJWTClaimsSchema
API key creation requestsCreateApiKeyRequestSchema
API key DB rowsApiKeyRowSchema
User tier DB rowsUserTierRowSchema

Layer 4: Data Storage

  • D1 (SQLite): All queries use .prepare().bind() — never string interpolation
  • KV: Scoped Worker bindings — no global credentials
  • R2: User-scoped key prefixes (clerk_user_id/...) prevent cross-user access

Layer 5: Angular Frontend

  • Auth state: Managed via Clerk Angular SDK — never localStorage
  • Route guards: Functional CanActivateFn guards enforce auth requirements
  • HTTP interceptor: Automatically attaches Bearer token to all authenticated requests
  • Response validation: Zod schemas validate all API responses before consumption

CORS Policy

Endpoint PatternPolicyRationale
/api/version, /health, /metrics, config endpoints* (public)Read-only, no auth
/compile*, /workflow/*, /queue/*Origin allowlistAuthenticated write
/rules, /api-keys (CRUD)Origin allowlistAuthenticated data
/admin/*Origin allowlistAdmin-only

The allowlist is centralized in worker/utils/cors.ts and configurable via the CORS_ALLOWED_ORIGINS environment variable.

Auth Tiers

TierRate LimitAccess
AnonymousLowestPublic read-only endpoints
FreeStandardCompile, validate, basic API
ProElevatedAll features, higher limits
AdminHighestAdmin endpoints, management

Security Telemetry

All security events are emitted to Cloudflare Analytics Engine:

  • auth_failure — JWT/API key verification failed
  • rate_limit — Rate limit exceeded
  • turnstile_rejection — Turnstile human verification failed
  • cors_rejection — Origin not in allowlist
  • cf_access_denial — CF Access JWT invalid
  • size_limit — Request body size exceeded

CI Enforcement

The zta-lint.yml workflow runs on every PR and checks for:

  1. Wildcard CORS (Access-Control-Allow-Origin: *) outside cors.ts
  2. Unparameterized D1 queries (string interpolation in .prepare())
  3. Secrets in wrangler.toml [vars]
  4. Auth tokens in localStorage

The api-shield-scan.yml workflow runs on every PR touching the OpenAPI spec and checks for:

  1. operationId coverage on all operations (required for scanner call graphs)
  2. security: annotations on resource endpoints
  3. cloudflare-schema.yaml drift from openapi.yaml
  4. Clean spec validation