Skip to main content

DocsSecurity & boundaries

Security and data boundaries

Place credentials, public forms, respondent identity, files, webhooks, deletion, and deployment on the right trust boundary.

View as Markdownllms.txt for agents

Start with the boundary model

Fillo separates the authenticated management plane from the public respondent plane. Dashboard reads and writes are anchored to a signed-in user's live workspace membership and role. Form, response, file, upload, publishable-key, connection, and integration records are scoped through that workspace rather than trusted from a client-supplied id.

Owner or admin authority is required for workspace configuration, connections, publishable and identity keys, CLI tokens, webhooks, integrations, and form or response deletion. Workspace deletion is owner-only. Management pages return not found for inaccessible form ids so they do not reveal another workspace's records.

  • A stale active-workspace value does not keep access after membership is removed; membership is checked again.
  • A newly provisioned preview workspace is capped and its signed browser claim cookie grants read-only access until a signed-in user completes the ownership claim.
  • Respondent identity, even when verified, never grants dashboard or workspace access.

Keep each credential in the right place

CredentialCapabilityHandling
Account sessionAuthenticated dashboard access within current workspace membership and role.Let the browser and Better Auth manage it. Do not forward session material to embeds or webhooks.
pk_ publishable keySync code-defined schemas into one workspace. It cannot read responses or perform general management.Safe in a client bundle. Origin rules reduce accidental browser use but are not caller authentication.
fcli_ CLI or Zapier tokenPrivate management access bound to one user and workspace while owner or admin authority remains active.Keep in a secret store, local CLI config, or Zapier connection. Plaintext is shown once and Fillo stores a hash.
is_ identity secretSigns respondent external ids so Fillo can distinguish verified identity from an in-page claim.Keep on your application server. Never expose it in browser code or a response.
Webhook signing secretLets your receiver authenticate one form's webhook body.Store on the receiving server and verify the raw request bytes before parsing.
Upload, draft, resume, and claim bearersAuthorize one narrow session, saved draft, resume action, or ownership claim.Treat possession as access. Keep them out of logs, analytics, screenshots, and unrelated storage.
Storage and integration credentialsLet Fillo verify uploads, open member-authorized files, or deliver to a connected service.They stay server-side. App-used provider credentials are encrypted at rest; the browser receives only a scoped upload capability.

A publishable key is intentionally public

Seeing a pk_ key in browser code is expected, not itself a secret leak. Origin restrictions can reduce accidental use, while review-before-publish on claimed live forms keeps a public sync call from changing production immediately.

Published forms are a public surface

Anyone with a published form id or slug can fetch its schema and submit through the cross-origin public API without a key. Drafts are available only to an authenticated workspace member for builder preview. A claimed live form keeps staged code-sync changes private until an owner or admin publishes them.

  • Do not put API secrets, internal credentials, private instructions, or sensitive defaults in labels, options, hidden fields, custom config, or any other schema property.
  • A hard-to-guess form id is not access control. Fillo's current published-form contract is appropriate for public or app-embedded collection, not a private server-only intake endpoint.
  • The public response, draft, session, and upload routes enforce body caps, schema validation, rate limits, workspace state, and resource binding. Honeypot and timing checks reduce simple spam but do not prove a respondent is human.
  • If your product must decide who may see or answer a form, enforce that in the host product and design the data flow knowing the published Fillo API remains public.

Verify respondent identity on your server

By default, identify({ id, email, name, traits }) is an unverified claim from the embedding page. It is useful for grouping and soft deduplication, but any script on that page can make the same claim.

Enable identity verification in workspace settings, keep the is_ secret on your server, and send a hex HMAC-SHA256 of the stable external id. Once enforcement is on, a missing or invalid hash causes Fillo to drop the identity and store the response as anonymous. The answers may still be accepted.

  • Use a stable host-app user or account id, not an email address that may change.
  • Verification protects respondent attribution and verified resume behavior. It is not login, authorization, or proof that an answer is truthful.
  • A responseLimit keyed by an email or phone field is a self-claim and only soft deduplication. Browser limits are device-local.
sign identity on your server
import { createHmac } from "node:crypto";

export function filloRespondent(user: { id: string; email: string }) {
  const secret = process.env.FILLO_IDENTITY_SECRET!;
  return {
    id: user.id,
    email: user.email,
    hash: createHmac("sha256", secret).update(user.id).digest("hex"),
  };
}

Keep file capabilities scoped

For Google Drive, S3-compatible storage, and Box, respondent bytes upload from the browser to the workspace's connected provider. Fillo creates a session bound to the workspace, form, field, filename, type, size, provider generation, and an unguessable bearer. Completion is verified server-side before the file reference can enter a response.

  • Fillo stores file metadata and provider references, not a long-term duplicate of the file contents. Authenticated Drive or Box downloads may stream through Fillo so a workspace member can open them.
  • Response file URLs require workspace access. Do not present them downstream as public download links.
  • Keep the original provider connection available while historical files need to open or be deleted. Cleanup fails closed when provider access is unavailable.
  • S3 and R2 require the permission, CORS, multipart recovery, versioning, and permanent-delete checks in Prepare an S3 or R2 bucket.
  • Do not assume uploaded content has been malware-scanned. Add scanning, DLP, retention, and regional controls in the connected provider or your own workflow when required.

Authenticate every webhook delivery

  • Production webhook URLs must use HTTPS. Fillo rejects embedded URL credentials, private or internal destinations, DNS results that include private addresses, and redirects.
  • Verify X-Fillo-Signature as hex HMAC-SHA256 over the exact raw body with the webhook secret. Compare equal-length values with a timing-safe function.
  • Commit the verified payload and X-Fillo-Delivery-Id to a durable inbox with a uniqueness constraint before acknowledging, then process it with separate retries. For database-only work, record the id and mutation in one transaction. Delivery is at least once and a response id may have separate created and updated events.
  • The signature authenticates integrity and origin; it does not encrypt the payload. TLS protects it in transit, and your receiver controls storage and onward access.
  • A webhook payload or integration may create a second copy outside Fillo. Apply retention, access control, redaction, and deletion procedures at that destination.

Use the complete receiver example

The Webhook guide includes raw-body verification, the header contract, payload shapes, retry timing, and idempotency guidance.

Plan deletion across every destination

For the hosted service's current processing terms, retention detail, and subprocessors, read the Privacy policy, Data Processing Agreement, and Subprocessors.

  • Deleting a response first removes its managed file objects from connected storage. If provider cleanup fails, Fillo keeps the database record so the deletion can be retried instead of silently orphaning bytes.
  • Erasing a respondent removes the workspace profile, saved drafts tied to that external id, and identity snapshots. Answers can stay de-identified, or a manager can also delete that person's responses and linked files.
  • Workspace and account deletion use a 21-day grace period. A scheduled workspace stops accepting responses immediately and may be cancelled by its owner until destructive cleanup begins. A scheduled account is gated to cancellation; only workspaces where that user is the sole owner are scheduled with it.
  • After the grace, workspace purge removes provider files before deleting workspace records. If provider cleanup is unavailable, the workspace remains scheduled and a later sweep retries it.
  • Saved-progress drafts expire 7 days after the last change and are deleted on submit or Start over. Structured delivery and diagnostic telemetry is generally retained for up to 90 days.
  • Fillo cannot retract a CSV, email, webhook event, Sheets row, Notion page, Zapier task, provider backup, or other copy already accepted outside Fillo. Delete those through the destination's own controls.

Secure a self-hosted deployment

The reference deployment is a long-running Node container backed by Postgres. It runs migrations at boot and uses in-process sweeps for webhook retries, abandoned drafts, retention, storage recovery, and deletion. A request-only or sleeping runtime needs an equivalent always-on scheduling design.

  • Keep secrets in the deployment platform's secret manager and out of image layers, source control, build logs, client environment variables, and telemetry.
  • Plan before rotating BETTER_AUTH_SECRET: existing encrypted provider credentials depend on the derived key and may need migration or reauthorization.
  • Patch the app, Postgres, base image, and provider policies; monitor health checks, error reports, outbox failures, purge deferrals, and storage recovery.
  • Self-hosting shifts TLS termination, database encryption, backups, availability, incident response, email reputation, and infrastructure access control to the operator.
RequirementWhy it matters
DATABASE_URLUse durable Postgres with restricted network access, encryption, monitored capacity, and a tested backup and restore policy.
BETTER_AUTH_SECRETUse at least 32 high-entropy characters and keep it stable. It signs auth state and derives provider-credential encryption keys.
APP_URLSet the exact public origin. Non-loopback production deployments must use HTTPS.
RESEND_API_KEY and EMAIL_FROMRequired together for public production because verification, reset, claim, and optional respondent emails depend on delivery.
Optional provider pairsConfigure both values for Google, Box, Notion, or Picker credentials. Half-configured integrations fail at boot.
Production-safe flagsNever enable test auth, private-webhook, shortened-abandonment, or E2E hooks in production. Fillo refuses them on a non-loopback production origin.

Do not infer guarantees the product does not make

  • This guide does not claim SOC 2, ISO 27001, HIPAA, PCI DSS, or another certification, nor does it make a compliance or uptime guarantee.
  • Encryption in transit and at rest is not end-to-end encryption. The application must process schemas, answers, and delivery payloads to provide the service.
  • Customer-owned file storage does not mean Fillo processes no data. Fillo stores response records, file metadata and references, upload session state, and delivery state.
  • Identity verification authenticates an external-id claim only. It does not authenticate the respondent to your product, authorize an action, or validate answer accuracy.
  • Origin allowlists, form ids, browser response limits, spam heuristics, and rate limits are defense layers, not strong caller identity.
  • Before collecting regulated or highly sensitive data, complete your own legal, security, retention, provider, and threat assessment and configure every downstream destination accordingly.

Next steps

Was this page useful?

Was this page helpful?
Powered by Fillo