ClipSpacesClipSpaces Docs
Back to app

All releases

Security hardening pass

Resolves the findings from a full security & scalability audit. No user-facing behaviour changes for the normal signed-in flow.

Security

  • SSRF protection (lib/net-guard.ts, new). Every server-side fetch of a user-supplied URL now validates scheme (http/https only) and rejects hosts that resolve to private/loopback/link-local ranges (incl. 169.254.169.254 cloud metadata) — enforced both pre-flight and at connect time via an undici dispatcher (defeats redirect-to-internal + DNS rebinding). Applied to /api/unfurl (open-graph-scraper wired to the guarded dispatcher) and to the AI link/PDF enrichment fetches (lib/ai-enrich.ts).
  • Rate limiting (lib/rate-limit.ts, new). Per-IP fixed-window limits on /api/unfurl, /api/github, /api/embed, /api/geocode (30/min) and /api/ai (20/min).
  • AI cost/abuse gate (app/api/ai/route.ts). The AI route now requires a signed-in user before falling back to the host's API key; self-host single-user deploys opt back in with ALLOW_ANON_AI=1.
  • Open redirect fixed (app/auth/confirm/route.ts). The next param now rejects protocol-relative (//host) and backslash forms.
  • Stored-XSS hardening (lib/safe-url.ts, new). Card URL fields are scrubbed on ingestion from untrusted peers/imports, and anchor href / iframe src values are guarded at render so a javascript: URL can't execute.
  • Security headers (next.config.mjs): X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy.
  • Config-file admin gate (app/api/ai/config-file/route.ts): optional AI_CONFIG_ADMIN_EMAILS allowlist for writing the shared host config.
  • Defense-in-depth: bounded the in-process caches (unfurl/geocode/ai-enrich), capped AI enrichment fetch concurrency, added a user_id filter to Notion disconnect, and added an ai_messages retention trigger (keeps the latest 400 per space) — supabase/migrations/20260702000100_ai_messages_retention.sql.