Skip to main content

Documentation Index

Fetch the complete documentation index at: https://formbricks.com/docs/llms.txt

Use this file to discover all available pages before exploring further.

Context

XM analytics reads Hub feedback records through Cube. Hub stores all tenants in a shared feedback_records table and uses tenant_id to separate rows. Workspace access is the application authorization boundary. In the current Hub schema, tenant_id stores the authorized FeedbackDirectory ID, so every Cube query must be scoped to a directory that the authenticated workspace can access before data leaves Cube.

Threat Model

The main risk is cross-tenant read access through an unscoped Cube query. The attacker could be a regression in server code, an AI-generated query that includes malicious filters, a copied static token, or a direct request to Cube from inside the deployment network. The controls assume query bodies are attacker-influenced. Tenant identity is never trusted from the query JSON.

Enforcement Flow

1

Authorize workspace access

Server actions and server components authorize workspace access in the Next.js app.
2

Validate the Cube query

The app validates the Cube query and rejects any FeedbackRecords.tenantId member supplied by users, saved charts, or AI output, including filters, dimensions, time dimensions, and order clauses.
3

Mint a short-lived JWT

The app mints a short-lived JWT per Cube request with tenantId, feedbackDirectoryId, workspaceId, organizationId, userId, scope, iss, aud, jti, and exp claims.
4

Verify the JWT in Cube

Cube verifies the JWT and exposes the claims through securityContext.
5

Enforce the tenant filter

Cube queryRewrite rejects missing tenant context, rejects caller-supplied tenant member usage, and appends FeedbackRecords.tenantId = securityContext.tenantId to every query.

Audit Evidence

The app records a sanitized cubeQuery audit event for each Cube query attempt, keyed by the JWT jti. Cube also emits a structured audit log line from queryRewrite with tenant, feedback directory, workspace, organization, user, request ID, source, and queried member names. Raw filter values are intentionally omitted from both logs.

Operational Notes

CUBEJS_API_SECRET is a signing secret, not an access token. Do not pass it to clients or reuse it as a bearer token. Set CUBEJS_JWT_ISSUER and CUBEJS_JWT_AUDIENCE consistently for the web app and Cube so Cube rejects tokens minted for any other audience or issuer. Set CUBEJS_DEFAULT_API_SCOPES=meta,data for Cube deployments so GraphQL, SQL, and orchestration APIs are not exposed unless explicitly needed. Network isolation for Cube remains recommended, but JWT-backed queryRewrite is the mandatory data boundary.