# 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:

- **H3** — `rehype-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
