Skip to content

Security

Frontier’s security posture is built on a foundation of managed cloud services, complemented by application-level controls and a robust Software Development Lifecycle (SDLC) that incorporates automated security tools. This page details the primary security mechanisms in place, covering authentication, access control, data isolation, and vulnerability management.

User authentication for the Frontier platform, including the Dashboard and live call app, is handled by Clerk, a third-party identity provider. This includes support for Google social sign-in. It is important to distinguish this from Recall.ai’s OAuth integrations for Google or Microsoft, which are used solely to access calendar and meeting information (with read-only scopes like calendar.events.readonly and User.Read), and are not tied to app login.

Within the call processing backend, the Call Server (a set of Cloudflare Workers and Durable Objects) validates Clerk-issued JSON Web Tokens (JWTs) for authenticated requests. These JWTs carry an org_id claim, which is extracted for use in access control decisions. A robust RS256 signature verification process, including fetching Clerk’s JSON Web Key Set (JWKS), is implemented for the TranscriptStream WebSocket entry point, ensuring the authenticity and integrity of incoming tokens for real-time transcription. However, some other entry points within the Call Server currently use a decode-only JWT validation, which checks claims and expiry but does not verify the cryptographic signature.

Frontier implements multi-layered tenant isolation to prevent unauthorized cross-organizational data access.

  • Supabase (Postgres): Row-Level Security (RLS) policies are extensively applied to all core tables (e.g., calls, call_participants, faqs, knowledge_documents). These policies enforce that users can only access data belonging to their org_id, which is extracted from the authenticated Clerk JWT. For tables without a direct org_id column, RLS is implemented by joining to parent tables that do contain org_id.
  • Cloudflare D1 (SQLite database): D1 is used to store live call transcripts (raw transcript_words) and detected questions. While the calls and questions tables directly carry org_id, the transcript_words table relies solely on call_id as a foreign key to the calls table. D1 does not natively support RLS. Therefore, tenant isolation for transcripts is enforced exclusively by the application layer, ensuring that queries are always scoped by the authenticated user’s org_id and the specific call_id.
  • Cloudflare AI Search: When retrieving knowledge base entries, Cloudflare AI Search queries include a hard org_id metadata-equality filter. This is documented as the “primary security boundary” for the knowledge base. An additional defense-in-depth post-filter (verifyOrgIsolation) is also applied, logging and dropping any results whose org_id metadata unexpectedly mismatches the querying organization.
  • Cloudflare R2 (Object Storage): Knowledge and FAQ objects stored in R2 are namespaced by an org_id key prefix (e.g., [orgId]/faqs/faq-id.md), providing per-organization isolation at the object storage layer.
  • Cloudflare Vectorize (for Pinecone legacy path): For older vector indexes (Pinecone), queries are filtered by { org_id: orgId }. Pinecone records mirrored in the Supabase Postgres database also carry an org_id.
  • Supermemory: As an interim knowledge backend, Supermemory isolates data by a container tag built from the environment and orgId. Retrieval queries are further filtered by source_type and source_id metadata.
  • Cloudflare KV: Used for short-lived caches (e.g., knowledge retrieval results), KV keys are org-scoped to prevent cross-tenant cache bleed. The data stored here is derived content, not the source of record.
  • Durable Objects: Per-call Durable Objects (e.g., CallAgent, CallChatAgent, OrgAnswerAgent) inherently scope their state to a single call and implicitly to the organization associated with that call. The TranscriptStream Durable Object explicitly validates the org_id from the incoming JWT.

Frontier uses Doppler for managing all environment variables and secrets. There are two Doppler projects: frontier-infra for CI secrets and frontier-x for runtime application environments. Secrets are injected into Cloudflare Workers as environment variables at deploy time via dopplerhq/secrets-fetch-action in CI pipelines or doppler run locally. Sensitive configuration files like .env and .env.* are explicitly .gitignored to prevent accidental commitment to the repository. The only committed environment files are public Sentry DSNs and test placeholders that contain no real secrets.

Frontier relies on the default encryption mechanisms provided by its underlying cloud platforms and services:

  • Encryption in Transit (TLS): All network communication within and to the Frontier platform relies on TLS (Transport Layer Security) provided by Cloudflare Workers, Vercel (for the Dashboard), and Supabase.
  • Encryption at Rest: Data stored in Supabase Postgres, Cloudflare D1, R2, KV, Durable Objects, AI Search, and Vectorize is encrypted at rest by default through these providers.

Frontier integrates several tools and practices into its SDLC to manage vulnerabilities:

  • Static Application Security Testing (SAST):
    • CodeQL: Runs on a weekly schedule and in the merge queue (security suite only). CodeQL findings are advisory (continue-on-error: true) and are uploaded to the GitHub Security tab for review.
    • SonarQube Security: Provides security and reliability gating as part of the bun sonar:check-pr policy.
  • Dependency Scanning:
    • Dependabot: Configured for weekly updates of Bun ecosystem dependencies to address known vulnerabilities and keep packages current.
  • Security Bots:
    • Aikido (aikido-pr-checks[bot]): An active PR reviewer that provides inline comments on security and code quality.
    • Cursor BugBot (bun bugbot:check-all): Scans Pull Requests for security and stability issues.
  • Database Security:
    • Supabase Security Advisors: A CI workflow queries Supabase Security Advisors and will fail a merge if ERROR-level findings (e.g., disabled RLS in public schemas) are detected, providing a safety net for database configuration.

Frontier maintains a published Responsible/Coordinated Vulnerability Disclosure Policy (available via security.txt pointing to security@frontierx.ai). This policy outlines a contact method, PGP key availability, and a 90-day coordinated disclosure window.

Frontier’s overall security posture is a blend of controls inherited from its cloud service providers and controls directly implemented by the Frontier engineering team.

Control TypeInherited Controls (Provider Default)Owned Controls (Frontier Implementation)
Identity & AuthClerk (account management, MFA, JWT issuance)Clerk integration (auth enforcement in Dashboard, JWT validation in Call Server)
Access ControlSupabase RLS enforcement, Cloudflare network security/WAFSupabase RLS policies (org_id from JWT), AI Search/Vectorize metadata filters, R2 key prefixes, D1 application-level scoping, org-scoped KV caches
Secrets ManagementCloud provider secret storage mechanismsDoppler (secrets lifecycle, separation of concerns), .gitignore for local .env
EncryptionTLS (Cloudflare, Supabase, Vercel), encryption at rest (all providers)(GAP: Formal documentation of explicit posture beyond provider defaults)
Vulnerability Mgmt.Cloud provider security updates/patching, OS/runtime patchingSAST (CodeQL, SonarQube), Dependency scanning (Dependabot), Security bots (Aikido, BugBot), Supabase Security Advisors CI
Runtime SecurityCloudflare Workers sandboxing, DDoS protectionCall Server security headers (HSTS, CSP), Application-level input validation
Logging & MonitoringCloud provider audit logs, service health monitoringSentry (error reporting), Axiom (structured logging), custom metrics/alerts
Incident ResponseCloud provider incident response & disclosureResponsible Vulnerability Disclosure Policy, internal incident playbooks (WIP)
  • Critical Risk: Disabled Internal Worker Authentication: Internal worker-to-worker callback authentication within the Call Server is currently disabled at three entry points (apps/call-server/src/routes/worker-callbacks.ts). This is a known vulnerability that could allow unauthorized injection of fake detection results into active calls if callback URLs are known. A fix is documented but not yet applied.
  • Inconsistent JWT Validation: While the TranscriptStream WebSocket entry point performs full RS256 JWT signature verification, other critical Call Server entry points (CallChatAgent, QuickAnswerAgent, api/chat, answerAgentShared) use a decode-only validateJWT. This means the org_id used for tenant isolation in these paths is trusted from an unverified token, unless protected by an upstream verifying gateway.
  • Isolation Asymmetry in Cloudflare D1: D1 relies solely on application-level call_id and org_id scoping for tenant isolation, lacking the database-enforced RLS present in Supabase. A flaw in application query logic for D1 could lead to cross-tenant data exposure.
  • Development Mode Bypasses: JWT validation logic includes explicit bypasses for dev environments (e.g., allowing expired tokens or skipping signature verification). While these correctly fail closed in non-dev configurations, it’s critical to ensure production environments never inadvertently resolve to dev.
  • Gaps in Formal Documentation: Explicit details on encryption-at-rest posture, production TLS cipher policies, and results of third-party penetration tests are not yet formally documented. These are essential for a complete security review.