Encryption
Everything in transit and at rest. Postgres on Neon (us-east-1) with managed encryption keys. TLS 1.3 only on the edge.
- TLS 1.3 on every public endpoint, HSTS preload-listed.
- AES-256 at rest for the database and object storage.
- Per-row encryption is on the roadmap for sensitive workspaces.
Access control
Same allowlist applies to humans and agents. Every workspace operation goes through a single canonical access check. There is no agent-only or human-only surface.
- Magic-link auth for humans, OAuth 2.1 with DCR for agents.
- Workspace visibility tiers (private / org / unlisted / public) with deterministic precedence.
- Signed-agent inheritance scoped to a single org — agents can't cross org boundaries via their owner.
- API keys stored as SHA-256 hashes, never plaintext. Validation hashes the incoming key and looks up by hash — no plaintext compare anywhere in the auth path.
Audit logs
Every state-changing action lands in a per-workspace ledger that names the actor — human OR agent — explicitly. Read by humans for review, by agents over MCP for context.
- Per-workspace event stream, immutable, append-only.
- Actor type, scope, IP prefix, request ID on every entry.
- Webhook subscriptions emit the same events to your stack in near-realtime.
Dangerous-op gates
A short list of operations never executes on the first call. Two-key handshake required: agent gets a confirm token, surfaces it to its user, retries with the token. Used for billing changes and any irreversible op.
- Single-use confirm tokens, 60-second TTL, bound to {org, principal, operation, params}.
- Today gated: upgrade_plan, downgrade_plan. New tools that move money or widen access route through the same gate by default.
- Sudo mode for sensitive USER ops (15-minute elevated session, scope-bound).
Doc + data shape guards
TipTap doc bytes, depth, and node count capped on every write. Same caps for humans and agents. Real prose never trips the gate; runaway agents do.
- Single validateDocShape gate runs inside writeDocBody — covers MCP, REST, and collab flush.
- Hard caps on rows-per-workspace, workspaces-per-org, and webhook delivery rate (per plan tier).
- Doc-shape errors return structured codes the agent can recover from.
- DOMPurify-sanitized SVG with explicit tag + attribute allowlist. Comment bodies plain-text-only (no HTML, no markdown). Embeds limited to a static safelist (YouTube, Vimeo, Loom, Figma, CodePen, Gist).
Webhook security
Outbound deliveries are signed and replay-safe. Receivers verify in a few lines; subscriptions stay scoped to the org that owns the events.
- HMAC-SHA256 signing — every delivery signs `{timestamp}.{body}` with the org's webhook secret and surfaces both in `x-dock-signature: t=…, v1=…`.
- Receivers reject stale deliveries by checking timestamp tolerance — replay protection without a separate nonce.
- Subscriptions org-scoped; org admins control creation and rotation. Failed deliveries retry with exponential backoff (1s → 24h, 8 attempts).
Network safety
Every URL we dispatch to from your data — webhooks, embed lookups, OG fetchers — is resolved and validated against private network destinations before we send a byte.
- DNS-resolved + checked against private ranges (10/8, 172.16/12, 192.168/16, 169.254/16), loopback, IPv6 link-local, cloud metadata IPs (169.254.169.254 + variants), and `.local` / `.internal` / `.arpa` suffixes.
- Production only allows `https://` destinations.
- Two-layer validation: cheap format check at save time, full DNS check at dispatch time — catches DNS-rebinding.
Transport & browser policy
Headers and cookies are tuned to keep your session out of reach of clickjackers, mixed-content downgrades, and stray browser features.
- HSTS preload-listed, 1-year max-age, includeSubDomains.
- X-Frame-Options DENY plus frame-ancestors `'none'` in CSP — no clickjacking.
- Permissions-Policy denies camera, microphone, geolocation, interest-cohort.
- Session cookies httpOnly + sameSite=Lax + secure (production).
Logging hygiene
Credentials and authorization headers are scrubbed before logs leave the request. Two layers cover both structured fields and bare strings.
- Field-name blocklist scrubs by name (`password`, `token`, `secret`, `api_key`, `session_token`, `accessToken`, `refreshToken`, …) before logs reach Vercel or Sentry.
- Credential-shape regex catches Bearer tokens, webhook secrets, JWT-shaped strings, and Vercel Blob tokens in stringified output.
- Request bodies are never logged in full; request IDs correlate actions without exposing actor identity.
Privacy by default
Your workspace data is yours. No AI or LLM is connected to Dock. The only agents that read your data are the ones you bring and authorize. We don't train on your data, don't share it, don't sell it.
- No AI or LLM connected to Dock's software.
- No model fine-tuning on customer data.
- Subprocessors limited to infrastructure (database, email, payment, error monitoring).
- Right-to-delete request honored within 30 days of receipt.