Skip to main content
Plain-English account of Forepost’s security posture. Detailed engineering reference (with code citations) is in the internal Engineering Reference; this page is the customer-facing summary.

Authentication

Forepost uses Clerk on a custom domain (clerk.forepost.ai). Every API request from the SPA carries a Clerk-issued JWT:
  • Verified server-side using the JWKS public keys from Clerk
  • Algorithm pinned to RS256
  • iss claim must match Forepost’s configured issuer
  • azp (authorized party) claim must be https://app.forepost.ai, no other Clerk application’s tokens are accepted
  • exp and nbf claims enforced
  • JWKS keys cached for 1 hour, then re-fetched (so revoked keys cannot be honoured indefinitely)
When auth fails, the worker returns 401 with a structured reason field, iss_mismatch, expired, bad_signature, azp_not_allowed, etc. This makes deploys debuggable without leaking internal state.

Authorization

There’s currently one role: the workspace owner. A user can only read or write their own workspace, subscription, briefs, and history, keyed by Clerk user ID. There is no team or admin role yet.

Email ownership

Subscribing the Daily Brief to an email address requires that address to be verified on your Clerk account. Forepost queries Clerk’s Backend API to confirm before saving. This stops the system being used to send mail to addresses you don’t own.

Rate limiting

Per-user, sliding-hour windowed counters in D1:
EndpointLimit
AI proxy (POST /)60 / hour
POST /brief/send5 / hour
POST /brief/send-digest5 / hour
Rate-limited responses return HTTP 429.

Transport security

  • All traffic is HTTPS only.
  • HSTS is set with max-age=63072000; includeSubDomains; preload.
  • TLS 1.3 with modern ciphers (managed by Cloudflare and Vercel).

Browser security headers

The SPA at app.forepost.ai ships with:
  • Content-Security-Policy: strict allowlist; default-src 'self'; explicit script-src and script-src-elem; frame-ancestors 'none' (clickjack-proof).
  • X-Content-Type-Options: nosniff
  • X-Frame-Options: DENY
  • Referrer-Policy: strict-origin-when-cross-origin
  • Permissions-Policy: camera, microphone, geolocation, FLoC all disabled.

Input validation

Every write endpoint validates incoming data before any database write or upstream API call:
  • Workspace JSON: allowlisted keys, type checks per field, 16 KB total cap, 50-agent maximum
  • Brief subscription: email regex + 254 char cap, IANA timezone, hour 0-23
  • AI proxy: system prompt and message content size caps, max-token cap of 1024
Unknown keys are rejected outright. No silent acceptance.

Email integrity

Outbound mail is sent via Resend with full DNS alignment on forepost.ai:
  • SPF: v=spf1 include:amazonses.com ~all
  • DKIM. Resend-managed, signed with d=forepost.ai
  • DMARC: published; currently p=none with reporting (rua=); will tighten to quarantine then reject after a clean reporting period
Every email carries a List-Unsubscribe header for one-click opt-out.

Unsubscribe tokens

Unsubscribe links are HMAC-SHA-256 signed with a server-side secret. Forging or replaying a token to disable someone else’s subscription is computationally infeasible. Verification is constant-time.

CORS

The API is locked to app.forepost.ai (and local-dev origins). Cross-site browser calls from any other origin are rejected.

Cross-app token isolation

Even if a token were issued by Clerk for some other application sharing the same Clerk instance, our azp allowlist rejects it. There’s no way for a Clerk JWT not minted for Forepost to authenticate against the worker.

What’s not yet in place

  • SOC 2 Type II. Planned. The controls outlined here are the substrate; the audit confirms them externally.
  • SAML SSO for Enterprise. On the roadmap; Clerk supports it natively.
  • Bug bounty. Not yet stood up. For now, security disclosures go to security@forepost.ai.

OWASP Top 10 (2021) — stance

The Forepost Worker has been spot-audited against each category. Summary below; details on request.
CategoryStance
A01 Broken Access ControlEvery endpoint resolves the caller via Clerk JWT → user_id, then keys all reads/writes on that user_id. Admin endpoints additionally gated by an ADMIN_USER_IDS env-var allowlist. Workspace members get scoped read access via the membership table, never cross-workspace.
A02 Cryptographic FailuresJWT verification with RS256 + JWKS rotation (1-hour cache); HMAC-SHA-256 on unsubscribe tokens with constant-time verification; helpdesk OAuth secrets encrypted with AES-GCM at rest; HTTPS only on every surface.
A03 InjectionAll D1 queries use prepared statements with bind() — no string-concatenated SQL anywhere. HTML in outgoing email rendered via a dedicated escapeHtml. Slack webhook URLs validated against a strict regex (hooks.slack.com/services/... only) on both save and send.
A04 Insecure DesignHonest-no-data principle prevents fabricated outputs. Email-ownership check (against Clerk’s verified addresses) before subscribing. Per-user rate limits per endpoint scope. Workspace JSON capped at 16 KB; agent count capped at 50.
A05 Security MisconfigurationCORS strictly allowlisted to app.forepost.ai. Strict CSP, X-Frame DENY, X-Content-Type-Options nosniff, Referrer-Policy strict-origin-when-cross-origin, Permissions-Policy locked down. Generic 500 returned on uncaught errors — no stack traces in responses.
A06 Vulnerable + Outdated ComponentsDependabot enabled (npm + GitHub Actions); weekly minor/patch grouped PR, monthly Action bumps. The worker’s runtime dependencies are minimal (Cloudflare runtime + Anthropic SDK pinned via package-lock).
A07 Authentication FailuresClerk handles authentication. Forepost verifies iss, azp (cross-app token isolation), exp, nbf on every request. No password storage of any kind.
A08 Software + Data IntegrityProduction worker deploys exclusively via GitHub Actions on merge to main, using a scoped Cloudflare API token. npm ci enforces package-lock hashes. No arbitrary code execution paths.
A09 Logging + MonitoringAll admin write actions append to admin_audit_log in D1. Cloudflare Workers observability is enabled for traffic + error metrics. Gap: no on-call alerting on error-rate spikes yet — operational rather than security, but flagged.
A10 Server-Side Request ForgeryThe worker makes outbound requests to a small set of hardcoded destinations (Anthropic, Clerk, Resend, helpdesk OAuth endpoints, JWKS). The only user-controlled outbound URL is the Slack webhook, host-restricted to hooks.slack.com. No fetch(userControlledUrl) anywhere.
The audit is repeated at least quarterly and after any change touching authentication, the cron, or outbound integration code.

Reporting a vulnerability

Email security@forepost.ai. We respond within 24 hours, fix critical issues within 7 days, and credit reporters in the changelog if they want acknowledgement.