Commit Graph

2 Commits

Author SHA1 Message Date
Yo-LRK 392a971270 security: gate unexpected-error detail to clients (residual low)
Follow-up to the traceback gate: client-facing exception detail is now gated too.

- safe_error(e) (app/utils/security.py): returns the exception string only when
  FLASK_DEBUG, otherwise a generic message. Full detail stays in server logs.
- All catch-all `except Exception` handlers in api/{graph,report,simulation}.py now
  return safe_error(e) instead of str(e); same for the persisted error fields
  (project.error / state.error / task fail messages). Typed `except ValueError`
  validation handlers (404/400) keep str(e) — those are intentional, actionable
  user messages that echo only user-supplied ids.
- graph_builder no longer puts a full traceback into the task error (logs it
  server-side with exc_info, surfaces safe_error to the client); the batch-failure
  progress message is gated too.
- README documents the CSP connect-src ↔ VITE_API_BASE_URL coupling.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 18:23:03 +07:00
Yo-LRK ed840c7a00 security: H5 traceback gate + MED tier (upload sniff, path validation, CSP)
H5 (traceback leak, completing the prior log-level fix): new app/utils/security.py
safe_traceback() logs the full stack server-side and returns it to clients only when
FLASK_DEBUG; all 53 traceback.format_exc() in api/{graph,report,simulation}.py now call
it (import traceback removed).

Upload content sniff: upload_content_ok() magic-byte check — pdf must start %PDF-,
txt/md/markdown rejected if they contain NUL bytes (BOM-prefixed UTF-16/32/8 text
allowed). Wired into the graph.py upload loop so a renamed binary can't pass the
extension whitelist.

Path validation: validate_id() (^[A-Za-z0-9_-]{1,64}$) blocks traversal before every
id->filesystem sink — ProjectManager._get_project_dir, SimulationManager._get_simulation_dir,
ReportManager._get_report_folder + the two Report*Logger __init__, and a new
SimulationRunner._run_dir() that all RUN_STATE_DIR joins route through.

CSP / security headers: CSP <meta> in index.html, vite preview.headers
(X-Frame-Options/nosniff/Referrer-Policy + CSP frame-ancestors), and a Flask
after_request that sets the same headers on API responses.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 18:00:28 +07:00