Files
platform/SECURITY_FIXES.md
T

3.5 KiB

Security Fixes Log

Tracks remediation progress against findings in SECURITY_AUDIT.md.


C1. Weak JWT Secret — FIXED

Ref: SECURITY_AUDIT.md > C1

Changes:

  • src/servers/jwt.ts — Added startup guard that throws if JWT_SECRET is absent or shorter than 32 characters
  • .env.example — Updated placeholder to <generate with: openssl rand -base64 32>

Note: The actual .env secret must be rotated manually per deployment.


C2. Global CORS Wildcard on All API Routes — FIXED

Ref: SECURITY_AUDIT.md > C2

Changes:

  • src/servers/hono.ts — Replaced origin: '*' with dynamic origin validation using the ALLOWED_ORIGINS allowlist from origin-validation.ts

C3. Server-Settings Routes Entirely Unauthenticated — FIXED

Ref: SECURITY_AUDIT.md > C3

Changes:

  • src/servers/hono.ts — Moved serverSettingsRouter inside protectedRouter
  • src/servers/api/server-settings/server-settings.ts — Added Super Admin role checks on all write operations
  • src/servers/_middlewares/super-admin-middleware.ts — New middleware for Super Admin enforcement
  • Exempted GET /api/server-settings/onboarding-complete as public (mounted before auth)

C4. Unauthenticated Dev-Server WebSocket Proxy — FIXED

Ref: SECURITY_AUDIT.md > C4

Changes:

  • src/servers/api/dev-server/router.ts:
    • Replaced slug-based proxy URLs with server-generated UUID v4 (proxyId). Proxy lookup is now by UUID, eliminating cross-user slug collisions.
    • Added proxyIdIndex map for O(1) lookup and pendingStarts guard against duplicate spawns.
    • JWT validation required on HTML requests (Accept: text/html) — the iframe entry point. Sub-resources pass on proxyId alone (browsers can't add custom headers to native loads).
    • ?token= query param stripped before forwarding to dev server.
    • proxyOverrideScript extended to inject Authorization: Bearer headers on fetch/XHR and append ?token= on WebSocket connections, reading fresh tokens from localStorage.
  • src/server.tsx:
    • WebSocket upgrades require ?token= query param. Token stored in WSData.wsToken for deferred async validation in the open handler (Bun requires synchronous server.upgrade()).
    • devServerWebsocket.open validates JWT + blacklist check before opening upstream connection. Closes with code 4001 if invalid.
  • src/workspaces/officerdev/src/apps/Preview/PreviewProvider.tsx:
    • startServer and status check useEffect append ?token= to iframe URL using client.token.

Security model: Two-layer capability — proxyId (unguessable UUID) as primary token, JWT as defense-in-depth on entry points (HTML, WebSocket).


C5. AI Chat Messages Rendered with rehype-raw — LLM-Driven XSS — FIXED

Ref: SECURITY_AUDIT.md > C5

Changes:

  • Installed rehype-sanitize (v6)
  • src/workspaces/officerdev/src/apps/Chat/components/MessageBubble.tsx:
    • Added rehypeSanitize with a schema that strips <script>, <iframe>, <object>, <embed>, <form> tags and all on* event handler attributes
    • Applied to both ReactMarkdown instances (assistant messages + streaming bubble)
    • rehype-raw retained so legitimate HTML (tables, <details>, etc.) still renders — sanitized before hitting the DOM

Remaining

See SECURITY_AUDIT.md for the full list. Next priorities:

  • H3rehype-sanitize for the other 6 Markdown rendering locations
  • H1/H2 — Move token to HttpOnly cookies
  • H7/M5 — URL validation for git-clone/yt-dlp/scrape
  • H9/H10 — Rate limiting fixes