fix: address audit findings — session_id validation, streaming reset, state isolation

- Replace truncated 12-char UUID with full 32-char UUID (128-bit entropy)
- Add validate_session_id() regex check to prevent path traversal
- Add _check_session_id() guard on all 6 API endpoints
- Change _step_counter from module global to contextvars.ContextVar
- Filter None values from node_state before merging into agent_state
- Log save_session failures instead of silently swallowing them
- Add finishStreaming() in catch/finally blocks to prevent UI lockup
- Fix broken multiline docstring in chat() endpoint
This commit is contained in:
2026-05-23 09:08:53 +08:00
parent 1952d75f13
commit 93ad5e8876
5 changed files with 66 additions and 25 deletions
+18 -3
View File
@@ -5,6 +5,7 @@
import json
import os
import re
import uuid
import tempfile
from datetime import datetime, timezone
@@ -26,12 +27,20 @@ def _ensure_dir():
SESSIONS_DIR.mkdir(parents=True, exist_ok=True)
_VALID_SESSION_ID_RE = re.compile(r'^[a-fA-F0-9]{12,}$')
def validate_session_id(session_id: str) -> bool:
"""校验 session_id 仅含合法 hex 字符(防路径穿越)。"""
return bool(_VALID_SESSION_ID_RE.match(session_id))
def _session_path(session_id: str) -> Path:
if not validate_session_id(session_id):
raise ValueError(f"Invalid session_id: {session_id!r}")
return SESSIONS_DIR / f"{session_id}.json"
def generate_session_id() -> str:
return uuid.uuid4().hex[:12]
return uuid.uuid4().hex
def create_session(name: str = "", agent_state: Optional[dict] = None,
@@ -58,7 +67,10 @@ def create_session(name: str = "", agent_state: Optional[dict] = None,
def load_session(session_id: str) -> Optional[dict]:
"""按 ID 加载会话数据。未找到则返回 None。"""
_ensure_dir()
fp = _session_path(session_id)
try:
fp = _session_path(session_id)
except ValueError:
return None
if not fp.exists():
return None
with open(fp, "r", encoding="utf-8") as f:
@@ -132,7 +144,10 @@ def list_all_sessions() -> list[dict]:
def delete_session(session_id: str) -> bool:
"""按 ID 删除会话文件。"""
_ensure_dir()
fp = _session_path(session_id)
try:
fp = _session_path(session_id)
except ValueError:
return False
if fp.exists():
fp.unlink()
_session_log.info("删除会话", extra={"session_id": session_id})