Technical Documentation
Excalidraw Security Review
Excalidraw Security Review
Threat model summary
| Threat | Control | Location |
|---|---|---|
| Cross-user scene access | Supabase RLS on public.diagrams (owner_id = auth.uid()) | Migration diagrams policies |
| Plan bypass | Server-side diagrams_enforce_free_limits trigger + entitlement check on every RPC that operates on whiteboards | public.diagrams_enforce_free_limits |
| Secret leakage in scene JSON | Redaction on save + on export via src/lib/security/scene-redaction.ts | Scene write path |
| Malicious SVG on library import | src/lib/security/svg-sanitizer.ts strips <script>, event handlers, javascript: URLs, external entity refs, foreign content | Library import handler |
| XML external entity (XXE) on library import | JSON-only parsing; SVG parsed with DOMParser and stripped, never document.write | Library import |
| Prototype pollution via scene restore | Object spread only; no Object.assign onto shared prototypes; scene is treated as data | serialize.ts |
| SSRF via image fetch | Image URLs are internal signed URLs from Supabase Storage; user-provided remote URLs are refused during import | Image handler |
| Clipboard HTML injection | HTML pasted into text elements is sanitized to plain text | Excalidraw upstream + Falcon paste hook |
| Room link leakage | No hosted collaboration is enabled. Supabase Realtime rooms are gated by owner-only RLS on the diagram row | Realtime channel authorizer |
| Service-worker cache leakage | No service worker registered by Excalidraw in the reusable package | Bundle boundary |
| PNG/SVG metadata leakage | Export helpers do not embed session metadata; Falcon post-processes exports to strip Falcon metadata before download | excalidraw-board.tsx export path |
| Large scene DoS | Scene size cap (10 MB JSON, 5,000 elements Pro / 10,000 Pro Plus) enforced in trigger and before autosave | Save pipeline |
CSP guidance
Recommend default-src 'self'; img-src 'self' data: blob: https://*.supabase.co; style-src 'self' 'unsafe-inline'; script-src 'self' 'wasm-unsafe-eval'; connect-src 'self' https://*.supabase.co wss://*.supabase.co; worker-src 'self' blob:;.
Trusted Types can be enabled once the marketing bundle no longer inlines runtime scripts.
What is intentionally allowed
data:andblob:URLs for image previews.- Inline SVG rendering (sanitized).
What is intentionally denied
- Any AI network call other than the user-configured BYOK provider.
- Any Firebase, Google Analytics, or Excalidraw-hosted endpoint.
- Any remote font, script, or image outside Supabase Storage.