# Security Remediation Plan

Based on the External Data Handling security audit (April 2026). 17 findings total — 0 Critical, 2 High, 6 Medium, 6 Low, 3 Informational. Ordered by priority based on real-world exploitability and effort.

---

## Phase 1 — Data Exposure & XSS (High Priority)

### 1. L-4: Authenticate /uploads static file access
**Location:** `server.js:127`
**Risk:** Uploaded documents (vulnerability data, compliance files) served without authentication. Anyone with the URL can access them.
**Fix:** Replace `express.static('/uploads')` with a route handler that runs `requireAuth(db)` before streaming the file. Use `res.sendFile()` with the validated path.
**Effort:** Small — single route change.

### 2. M-6: Sanitize Mermaid SVG output with DOMPurify
**Location:** `frontend/src/components/KnowledgeBaseViewer.js:38`
**Risk:** Mermaid renders SVG which is injected via `innerHTML`. If KB content contains malicious markup, this is a stored XSS vector.
**Fix:** Install `dompurify`, sanitize the SVG string before assigning to `innerHTML`. Use `DOMPurify.sanitize(svgString, { USE_PROFILES: { svg: true } })`.
**Effort:** Small — add dependency, wrap one line.

### 3. M-4: Strip server file paths from compliance preview response
**Location:** `backend/routes/compliance.js:278`
**Risk:** Full server-side file path returned to client. Helps attackers map the filesystem.
**Fix:** Return only the filename (use `path.basename()`) instead of the full path. Or return a reference ID that maps to the file server-side.
**Effort:** Small — one-line change.

---

## Phase 2 — Deployment & Setup Hygiene

### 4. H-2: Add SESSION_SECRET to .env.example and setup-env.sh
**Location:** `backend/.env.example`, `backend/setup-env.sh`
**Risk:** Fresh deployments fail with no guidance on required env vars.
**Fix:** Add `SESSION_SECRET=` to `.env.example` with a comment explaining it should be a random 64+ character string. Add generation logic to `setup-env.sh` (e.g., `openssl rand -hex 32`).
**Effort:** Small.

### 5. I-3: Set user_group on default admin in setup.js
**Location:** `backend/setup.js:180`
**Risk:** Default admin created without `user_group`, potentially locked out of `requireGroup`-protected routes on fresh install.
**Fix:** Set `user_group = 'Admin'` in the INSERT statement for the default admin user.
**Effort:** Trivial — one column added to the INSERT.

---

## Phase 3 — Error Message Sanitization (Batch)

### 6. L-2: Sanitize Python parser error messages
**Location:** `backend/routes/compliance.js:284`
**Risk:** Stack traces and server paths leaked to client when Python parser fails.
**Fix:** Catch the error, log the full details server-side, return a generic "Compliance file parsing failed" message to the client.
**Effort:** Small.

### 7. L-3: Sanitize Ivanti API error responses
**Location:** `backend/routes/ivantiFpWorkflow.js:393`
**Risk:** Raw Ivanti API error body forwarded to client, potentially exposing internal API details.
**Fix:** Log the raw error server-side, return a generic "Ivanti API request failed" message to the client.
**Effort:** Small.

### 8. L-6: Remove group name from requireGroup error response
**Location:** `backend/middleware/auth.js:60`
**Risk:** Error response leaks the user's current group name, which is minor info disclosure.
**Fix:** Change the error message from something like "User group 'Viewer' not authorized" to "Insufficient permissions."
**Effort:** Trivial.

---

## Phase 4 — Security Headers

### 9. M-1: Add Content-Security-Policy header
**Location:** `server.js:107-113`
**Risk:** No CSP means no browser-side XSS mitigation layer.
**Fix:** Add a CSP header via middleware. Start with a report-only policy to avoid breaking things, then tighten. Suggested baseline:
```
default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'
```
Note: `'unsafe-inline'` for styles is needed because the app uses inline style objects extensively. Evaluate whether `script-src 'self'` breaks anything (it shouldn't with CRA).
**Effort:** Medium — needs testing to ensure nothing breaks.

### 10. M-2: Add Strict-Transport-Security (HSTS) header
**Location:** `server.js:107-113`
**Risk:** No HSTS means browsers don't enforce HTTPS on subsequent visits.
**Fix:** Add `Strict-Transport-Security: max-age=31536000; includeSubDomains` header. Only apply when running behind HTTPS (check `req.secure` or a trusted proxy header). Do NOT enable if the app is accessed over plain HTTP.
**Effort:** Small, but verify deployment is HTTPS-only first.

---

## Phase 5 — Operational Maintenance

### 11. L-5: Add expired session cleanup
**Location:** `backend/middleware/auth.js:271`
**Risk:** Sessions table grows indefinitely. Not a security exploit, but degrades performance over time.
**Fix:** Add a cleanup function that runs on server startup (and optionally on a setInterval) to DELETE sessions where `expires_at < CURRENT_TIMESTAMP`. Run once at boot, then every 6 hours.
**Effort:** Small.

---

## Phase 6 — Session Signing (Larger Effort)

### 12. H-1: Use SESSION_SECRET for HMAC-signed session tokens
**Location:** `server.js:33`
**Risk:** Session tokens are random bytes stored in DB with no signing. An attacker with DB read access can replay any session. For self-hosted SQLite, DB access already implies full compromise, so this is a defense-in-depth measure.
**Fix:** When creating a session, generate a random token and store its HMAC (using SESSION_SECRET) in the DB. On validation, recompute the HMAC and compare. This means a DB dump alone isn't enough to forge sessions — the attacker also needs the secret.
**Effort:** Medium — touches session creation, validation, and requires SESSION_SECRET to actually be wired in.

---

## Phase 7 — Investigate Before Changing

### 13. M-3: Review application/octet-stream in MIME allowlist
**Location:** `server.js:62`
**Risk:** Allows uploads that bypass MIME type checking. May be intentional for specific file types.
**Action:** Check what file types are uploaded that resolve to `application/octet-stream`. If none are legitimate, remove it from the allowlist. If some are (e.g., `.db` files, binary exports), consider adding those specific MIME types instead.
**Effort:** Investigation first, then trivial change.

### 14. M-5: Evaluate CORS HTTP origin policy
**Location:** `server.js:38-40`
**Risk:** CORS allows HTTP origins, no HTTPS enforcement.
**Action:** Check if production runs behind a reverse proxy with HTTPS termination. If yes, the backend legitimately sees HTTP origins from the proxy. If production traffic is ever plain HTTP end-to-end, restrict CORS to HTTPS origins only.
**Effort:** Investigation first, then small config change.

---

## Phase 8 — Low Priority / Monitor

### 15. L-1: Add startup warning for IVANTI_SKIP_TLS=true
**Location:** `backend/helpers/ivantiApi.js:28`
**Risk:** TLS validation disabled silently. Acceptable in dev, risky if accidentally left on in production.
**Fix:** Add a `console.warn('⚠ IVANTI_SKIP_TLS is enabled — TLS certificate validation is disabled')` at startup when the flag is set.
**Effort:** Trivial.

### 16. I-1: Monitor react-scripts version
**Location:** `frontend/package.json`
**Risk:** Build-time only, not runtime. No immediate action needed.
**Action:** Upgrade to latest react-scripts when convenient. Consider migrating to Vite if a major frontend overhaul is planned.

### 17. I-2: Monitor xlsx dependency
**Location:** `frontend/package.json`
**Risk:** Community fork, unmaintained since 2022. Used for spreadsheet parsing.
**Action:** Monitor for security advisories. If a vulnerability is found, evaluate alternatives (e.g., `exceljs`, `sheetjs` pro). No immediate action needed unless a CVE is published against it.

---

## Summary

| Phase | Items | Effort | Impact |
|-------|-------|--------|--------|
| 1 — Data Exposure & XSS | L-4, M-6, M-4 | Small | High |
| 2 — Deployment Hygiene | H-2, I-3 | Small | Medium |
| 3 — Error Sanitization | L-2, L-3, L-6 | Small | Low-Medium |
| 4 — Security Headers | M-1, M-2 | Medium | Medium |
| 5 — Session Cleanup | L-5 | Small | Low |
| 6 — Session Signing | H-1 | Medium | Medium |
| 7 — Investigate | M-3, M-5 | Investigation | TBD |
| 8 — Monitor | L-1, I-1, I-2 | Trivial | Low |
