fix(agent-team): scrub exception text from /api/state + /api/topology errors
/sh-security-review confirmed SEC-DASH-001 (low): build_snapshot embedded str(exc) of a sqlite/OS error into the /api/state payload, leaking the absolute DB path / table names to the unauthenticated LAN surface. Return only type(exc).__name__ (matching the task_detail hardening); apply the same to /api/topology's error branch (SEC-DASH-003). Full exception detail stays in server-side logs.
This commit is contained in:
parent
6951bf2fc6
commit
a632a7df7d
2 changed files with 15 additions and 4 deletions
|
|
@ -258,7 +258,14 @@ def make_dashboard_app(db_path: str | Path | None = None) -> Any:
|
|||
try:
|
||||
payload = build_topology()
|
||||
except Exception as exc: # pragma: no cover - defensive
|
||||
payload = {"trees": [], "nodes": [], "edges": [], "error": str(exc)}
|
||||
# Type only, never str(exc) — keep internal LangGraph/import detail
|
||||
# off the unauthenticated LAN surface (SEC-DASH-003).
|
||||
payload = {
|
||||
"trees": [],
|
||||
"nodes": [],
|
||||
"edges": [],
|
||||
"error": type(exc).__name__,
|
||||
}
|
||||
return JSONResponse(payload, headers={"Cache-Control": "no-store"})
|
||||
|
||||
@app.get("/api/task/{thread_id}")
|
||||
|
|
|
|||
|
|
@ -298,19 +298,23 @@ def build_snapshot(db_path: Path | str | None = None) -> Snapshot:
|
|||
tasks = _read_tasks(resolved, thread_ids, open_by_thread)
|
||||
spend, spend_total, budget_available = _read_recent_spend(conn)
|
||||
except sqlite3.OperationalError as exc:
|
||||
# Locked / busy / unreadable — never crash, just say so.
|
||||
# Locked / busy / unreadable — never crash, just say so. Return only the
|
||||
# exception TYPE, never str(exc): a SQLite message can carry the DB path /
|
||||
# table names, and this payload is served unauthenticated on the LAN
|
||||
# (matches the task_detail hardening). [sh-security-review SEC-DASH-001]
|
||||
return Snapshot(
|
||||
generated_at=generated_at,
|
||||
db_path=str(resolved),
|
||||
ok=False,
|
||||
error=f"could not read ledger (busy or unreadable): {exc}",
|
||||
error=f"could not read ledger (busy or unreadable): {type(exc).__name__}",
|
||||
)
|
||||
except Exception as exc: # defensive: any unexpected read failure
|
||||
# Type only, never str(exc) — see SEC-DASH-001 note above.
|
||||
return Snapshot(
|
||||
generated_at=generated_at,
|
||||
db_path=str(resolved),
|
||||
ok=False,
|
||||
error=f"unexpected error reading ledger: {exc}",
|
||||
error=f"unexpected error reading ledger: {type(exc).__name__}",
|
||||
)
|
||||
finally:
|
||||
if conn is not None:
|
||||
|
|
|
|||
Reference in a new issue