**Scope:** Full-stack audit of server, frontend, and infrastructure code.
---
## Executive Summary
The codebase has solid foundations (JWT + argon2 auth, WebAuthn passkeys, token blacklisting, Docker-sandboxed terminals, role-based access control). However, several critical and high-severity vulnerabilities exist — primarily around CORS misconfiguration, weak secret management, unauthenticated admin routes, XSS via `rehype-raw`, and token exposure in URLs.
The live `.env` contains `JWT_SECRET="officer"` — a single dictionary word. The `.env.example` uses `"change-me"`. The server uses a non-null assertion (`JWT_SECRET!`) with no startup validation for length or complexity.
**Impact:** Complete authentication bypass. Anyone who knows/guesses the secret can forge JWTs for any user including Super Admin.
**Remediation:**
- Generate a cryptographically random secret: `openssl rand -base64 32`
- Add a startup guard: throw if `JWT_SECRET` is absent or shorter than 32 characters
- Update `.env.example` with a placeholder: `JWT_SECRET=<generate with: openssl rand -base64 32>`
Applied to every route. The `Authorization` header allowlist means any website can make cross-origin requests using a victim's token (obtained via XSS or other leaks).
**Impact:** Full cross-origin request forgery against all API endpoints for users tricked into visiting a malicious page.
**Remediation:** Replace `origin: '*'` with the allowlist from `origin-validation.ts` (`ALLOWED_ORIGINS`). Use a dynamic origin validation function in the CORS middleware.
The `serverSettingsRouter` is mounted on the **public** router (outside `protectedRouter`). All sub-routes — SMTP, TTS, STT, OCR, SearXNG, Pi-Mono, Claude Code, OpenCode, applications, resources — have no auth checks. Any unauthenticated request can read settings (including masked credentials), write new settings, and trigger software installs.
**Impact:** Full server configuration takeover by any unauthenticated user.
**Remediation:** Move `serverSettingsRouter` inside `protectedRouter`. Add Super Admin role checks on all write operations. Exempt only `GET /api/server-settings/onboarding-complete` as public.
The dev-server proxy (`/api/dev-server-proxy/*`) is mounted on the public router. WebSocket upgrades carry no authentication. The HTTP proxy has no auth gate either. Additionally, the Referer header fallback allows probing any running dev server.
**Impact:** Unauthenticated access to dev-servers spawned for any user, which may expose internal APIs, HMR endpoints, or local services.
**Remediation:** Require a valid JWT (via query param) before upgrading WebSocket connections. Apply `userMiddleware` to the HTTP proxy router.
---
### C5. AI Chat Messages Rendered with `rehype-raw` — LLM-Driven XSS
AI-generated assistant responses containing HTML tags (`<script>`, `<iframe>`, `<img onerror=...>`) are rendered verbatim into the DOM.
**Impact:** Stored XSS in the chat interface. Prompt injection via uploaded files, tool results, or a compromised AI provider can execute arbitrary JavaScript — exfiltrating the Bearer token from localStorage.
**Remediation:** Remove `rehype-raw` from chat rendering. If basic HTML is needed, use `rehype-sanitize` with an allowlist of safe tags (no `<script>`, `<iframe>`, event handlers).
The full 30-day JWT appears in URLs for WebSocket connections, raw file downloads, and media transcoding.
**Impact:** Tokens are logged by servers, proxies, CDNs; stored in browser history; sent in `Referer` headers; visible to browser extensions and analytics scripts.
**Remediation:** For WebSocket: send the token as the first message after connection. For media: use short-lived single-use tokens generated by a dedicated endpoint (e.g., 60-second TTL).
---
### H3. `rehype-raw` Used in Multiple Content-Rendering Contexts
HTML email bodies are written into an iframe via `document.write()` with `sandbox="allow-same-origin"`. While `allow-scripts` is not set (blocking script execution), CSS injection and phishing forms can still render.
**Impact:** Email phishing attacks rendered within the Officer UI. CSS-based data exfiltration possible.
**Remediation:** Change to `sandbox=""` (no attributes). Consider running email HTML through DOMPurify server-side.
---
### H5. Mass Email Template — Unsanitized `dangerouslySetInnerHTML`
User names are interpolated via `String.replace()` without HTML encoding. A user with `<script>` in their name triggers XSS in the admin's email preview.
**Impact:** Stored XSS in admin email previews.
**Remediation:** HTML-encode all interpolated user data. Use DOMPurify on the final output.
Both `yt-dlp` and `git clone` are invoked with user-supplied URLs without scheme validation. `git clone file:///etc/passwd` reads local files. `yt-dlp` accepts plugin URLs and SSRF targets.
**Impact:** Local file exfiltration via `file://`, SSRF to internal services, potential exploitation via git remote helpers.
**Remediation:** Validate URLs to allow only `http://` and `https://` schemes. Add `--` argument terminator and `--no-config` for yt-dlp. Add `--no-local` for git.
---
### H8. File Browser Exposes Host Filesystem to Super Admin
Super Admin can access `~` (host homedir) and `officer.dev` (project root), giving read/write access to `.env`, auth store files, API keys, and the entire host filesystem.
**Impact:** A compromised Super Admin account (or forged JWT — trivial with C1) has full host filesystem access.
**Remediation:** Restrict roots to `DATA_PATH` only. Remove `~` and `officer.dev` roots or restrict them to read-only with path filtering.
All rate limiters are bypassed unless `PUBLIC_BUILD_ENV` is `production` or `staging`. The `.env` doesn't set this variable, so rate limiting is off by default.
**Impact:** Unrestricted brute-force attacks on passwords, verification codes, and passkey challenges in any deployment that doesn't explicitly set `PUBLIC_BUILD_ENV=production`.
**Remediation:** Enable rate limiting by default. Only disable when `PUBLIC_BUILD_ENV === 'test'`.
The OAuth state is just `base64(JSON)` — no HMAC. The `origin` query parameter is user-controlled and embedded in the state. The callback is a public endpoint.
**Impact:** OAuth CSRF. An attacker can craft a state parameter to bind their Google account to a victim's email.
**Remediation:** Sign the state with HMAC using `JWT_SECRET`. Derive `redirectUri` from `PUBLIC_URL`, not from the query parameter.
---
### H13. `maxRequestBodySize` Set to 50 GB
**File:**`src/server.tsx` (line 144)
**Impact:** DoS by exhausting server memory/disk with a single request.
**Remediation:** Set a reasonable limit (100 MB–1 GB). Apply per-route size limits for file uploads.
Three endpoints run `curl | bash` or `npm install -g` on the host. Even after fixing C3, any authenticated user (not just Super Admin) can trigger installs.
**Remediation:** Restrict to Super Admin. Add integrity checks (SHA256 pinning).
---
### L8. Token Accepted via URL `officerToken` Parameter
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.