Skip to content

Security audit: Fix 7 vulnerabilities and add security headers#21

Merged
mriechers merged 2 commits intomainfrom
claude/security-audit-euA8r
Feb 10, 2026
Merged

Security audit: Fix 7 vulnerabilities and add security headers#21
mriechers merged 2 commits intomainfrom
claude/security-audit-euA8r

Conversation

@mriechers
Copy link
Owner

Summary

This PR addresses a comprehensive security audit of the Editorial Assistant codebase. 7 vulnerabilities have been fixed and 4 advisory findings are documented in the new SECURITY_AUDIT.md for future architectural decisions.

Fixed Vulnerabilities

Critical

  • Path Traversal in File Upload (api/routers/upload.py): Added sanitize_upload_filename() function that strips directory components, removes dangerous characters, and validates resolved paths to prevent writing files outside the transcripts/ directory.

High

  • Command Injection via shell=True (api/routers/system.py): Replaced subprocess.Popen(..., shell=True) with an allowlist-based approach using list-form subprocess calls. Only run_worker.py and watch_transcripts.py can be started.
  • Server-Side Request Forgery (SSRF) (api/routers/ingest.py): Added ALLOWED_INGEST_HOSTS allowlist to restrict ingest server URLs to mmingest.pbswi.wisc.edu, preventing probing of internal network addresses.

Medium

  • Error Message Information Disclosure (multiple files): Replaced all detail=str(e) patterns with generic error messages. Full exception details remain in server logs for debugging.
  • Airtable Formula Injection (api/services/airtable.py, mcp_server/server.py): Added _escape_airtable_formula_value() to escape single quotes and backslashes in media IDs before interpolating into Airtable filter formulas.
  • Gemini API Key Exposed in URL (api/services/llm.py): Moved API key from URL query parameter to x-goog-api-key HTTP header to prevent leakage in logs and error messages.
  • Missing Security Headers and Overly Permissive CORS (api/main.py): Tightened CORS to explicit method/header lists and added security headers middleware (X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, Referrer-Policy, Permissions-Policy).

Advisory Findings (Documented, Not Fixed)

Four high/medium-priority findings require architectural decisions:

  • No Authentication/Authorization: Entire API is unauthenticated; recommend Cloudflare Access + JWT or API key middleware
  • No Rate Limiting: Recommend slowapi middleware, especially for /api/chat/message and /api/upload/transcripts
  • WebSocket Without Authentication: Recommend token-based auth for WebSocket connections
  • Hardcoded sys.path: Recommend environment variables or proper package installation

Files Modified

  • api/routers/upload.py - Path traversal protection with filename sanitization
  • api/routers/system.py - Command injection fix with allowlist
  • api/routers/chat_prototype.py - Generic error messages
  • api/routers/ingest.py - SSRF protection with host allowlist
  • api/services/airtable.py - Formula injection escaping
  • api/services/llm.py - API key moved to header
  • api/main.py - Security headers and CORS tightening
  • mcp_server/server.py - Formula injection escaping
  • tests/test_ingest_api.py - Updated test URLs to use allowlisted host
  • SECURITY_AUDIT.md - New comprehensive audit report (152 lines)

Testing

Updated ingest API tests to use the allowlisted host (mmingest.pbswi.wisc.edu) instead of example.com. All fixes maintain backward compatibility with existing functionality.

https://claude.ai/code/session_018s8XVCwoprXPYHe1PjNRq9

[Agent: Main Assistant]

CRITICAL:
- Path traversal in file upload: sanitize filenames, add resolve() check

HIGH:
- Command injection: replace shell=True with allowlist + list-form subprocess
- SSRF in ingest scan: add hostname allowlist for base_url parameter

MEDIUM:
- Error disclosure: replace str(e) in HTTP responses with generic messages
- Airtable formula injection: escape single quotes in media_id values
- Gemini API key: move from URL query parameter to x-goog-api-key header
- CORS/headers: tighten CORS methods/headers, add security response headers

Also documents 4 advisory findings (no auth, no rate limiting, WS auth,
sys.path manipulation) in SECURITY_AUDIT.md for future consideration.

https://claude.ai/code/session_018s8XVCwoprXPYHe1PjNRq9
@mriechers mriechers self-assigned this Feb 7, 2026
@mriechers mriechers added the security Security vulnerabilities and hardening label Feb 7, 2026
@mriechers mriechers merged commit 629a8a5 into main Feb 10, 2026
3 of 5 checks passed
@mriechers mriechers deleted the claude/security-audit-euA8r branch February 10, 2026 04:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

security Security vulnerabilities and hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants