tldraw/tldraw
Security
Trust boundaries, authentication, content isolation, and licensing in the tldraw repo.
Trust boundaries in tldraw.com
graph LR
Browser[user browser] -->|wss / https| Edge[Cloudflare edge]
Edge --> SyncWorker[apps/dotcom/sync-worker]
Edge --> Client[apps/dotcom/client static]
Edge --> Asset[asset-upload-worker]
Edge --> Resize[image-resize-worker]
Edge --> UserContent[tldrawusercontent-worker]
SyncWorker -->|R2| R2
SyncWorker -->|sqlite| DOSqlite[(DO sqlite)]
Asset -->|R2| R2
Resize -->|R2| R2
Client -->|sync| ZeroCache[zero-cache]
ZeroCache -->|replication| Postgres[(Postgres)]Several boundaries are intentional:
tldrawusercontent-workerserves user-uploaded files under a separate domain to isolate untrusted content from the main tldraw.com origin. This is a standard "user content on a separate eTLD" defense against cookie/XSS leakage.asset-upload-workeris the only entry point that writes to the R2 asset bucket. The client uses signed URLs.image-resize-workeris read-only against R2.sync-workervalidates inbound records against the schema before applying them. If a client sends a malformed shape record,TLSyncRoomrejects the message viaTLRemoteSyncError.
Auth
The signed-in dotcom area (apps/dotcom/client/src/tla/) supports user authentication. Anonymous rooms (tldraw.com/r/<roomId>) are unauthenticated by design — anyone with the URL can join. This is a product choice; the underlying sync engine has no built-in authentication, so self-hosted deployments add their own.
For self-hosting, useSync accepts a headers callback so you can inject auth tokens:
useSync({
uri: 'wss://...',
roomId: '...',
// headers: async () => ({ Authorization: `Bearer ${await getToken()}` }),
});Embeds
The default embed list (packages/tldraw/src/lib/defaultEmbedDefinitions.ts) restricts embeddable content to a known allowlist (YouTube, Figma, GitHub, CodePen, …). Each entry has a sandbox attribute string that restricts what the embedded iframe can do. Custom apps can extend this list, but the recommended path is "extend the allowlist", not "render arbitrary URLs as iframes".
External content handlers
packages/tldraw/src/lib/defaultExternalContentHandlers.ts controls what happens when something is dropped, pasted, or uploaded. The defaults treat unknown content cautiously: unknown URLs become bookmarks, unknown text becomes plain text, unknown files are rejected.
License key
The SDK ships a license-key system under packages/editor/src/lib/license/. Production use of the SDK requires a key (from https://tldraw.dev/pricing). The watermark code in packages/editor/src/lib/watermarks.ts is what enforces this when no key is present. The license check is client-side and intentionally easy to circumvent — the license is a legal contract, not a DRM mechanism.
Sentry and PII
The dotcom client uses Sentry. The Sentry config (apps/dotcom/client/sentry.client.config.ts) configures sample rates and includes the release name from sentry-release-name.ts. Don't log user-identifiable data into errors; Sentry strips most fields by default but additional filtering is the developer's responsibility.
Reporting
SECURITY.md at the repo root documents how to report vulnerabilities. The short version: email security@tldraw.com.
Related
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.