Summary
CodeQL flagged py/stack-trace-exposure on restart_fleet during PR #1912, which fixed its own instance (response carries HTTPException.detail or the exception class name only; full message + traceback go to the backend log via exc_info=True — see the pattern at src/backend/routers/ops.py, the restart_fleet error branch). The same raw-str(e)-into-response pattern pre-exists at sibling sites that PR deliberately left untouched (minimal-changes rule):
- Open CodeQL alert #231:
src/backend/routers/system_agent.py:83 (ref main)
src/backend/routers/ops.py:205 — fleet health "Agent not responding: {str(e)[:50]}" (truncated, lowest risk)
src/backend/routers/ops.py:564 — stop_fleet per-agent "error": str(e)
src/backend/routers/ops.py:751 — _stop_agent_container "error": str(e) (feeds emergency_stop results)
src/backend/routers/ops.py:1056 — ops costs "Failed to fetch metrics: {str(e)}"
- (grep-worthy:
routers/agents.py single-agent stop/start raise HTTPException(500, f"...{str(e)}") — same class via detail)
All these endpoints are admin-gated, so exposure is bounded — but exception messages can embed internals (the #1885 reaped-cmdline and git-stderr-PAT classes, docs/memory/learnings.md 2026-07-14), and alert #39 (the restart_fleet instance on main) demonstrates CodeQL files them as findings.
Acceptance criteria
Found while resolving the code-scanning review on PR #1912 (#1860).
Summary
CodeQL flagged
py/stack-trace-exposureonrestart_fleetduring PR #1912, which fixed its own instance (response carriesHTTPException.detailor the exception class name only; full message + traceback go to the backend log viaexc_info=True— see the pattern atsrc/backend/routers/ops.py, therestart_fleeterror branch). The same raw-str(e)-into-response pattern pre-exists at sibling sites that PR deliberately left untouched (minimal-changes rule):src/backend/routers/system_agent.py:83(refmain)src/backend/routers/ops.py:205— fleet health"Agent not responding: {str(e)[:50]}"(truncated, lowest risk)src/backend/routers/ops.py:564—stop_fleetper-agent"error": str(e)src/backend/routers/ops.py:751—_stop_agent_container"error": str(e)(feedsemergency_stopresults)src/backend/routers/ops.py:1056— ops costs"Failed to fetch metrics: {str(e)}"routers/agents.pysingle-agent stop/start raiseHTTPException(500, f"...{str(e)}")— same class viadetail)All these endpoints are admin-gated, so exposure is bounded — but exception messages can embed internals (the #1885 reaped-cmdline and git-stderr-PAT classes,
docs/memory/learnings.md2026-07-14), and alert #39 (therestart_fleetinstance onmain) demonstrates CodeQL files them as findings.Acceptance criteria
exc_info=True) — the PR fix: fleet restart adopts rebuilt base images through the canonical lifecycle path (#1860) #1912 patternmainanalysis (alert Vectorized Episodic Memory #39 closes on its own once fix: fleet restart adopts rebuilt base images through the canonical lifecycle path (#1860) #1912 ships in a release — verify, don't re-fix)tests/unit/test_1860_fleet_restart_adoption.py)Found while resolving the code-scanning review on PR #1912 (#1860).