From b2e5b7e8de7c950c9c1be517407ba5d33dcba0f9 Mon Sep 17 00:00:00 2001 From: Sebastion Date: Mon, 27 Jul 2026 18:51:40 +0100 Subject: [PATCH] fix(api): don't leak stack traces in simulation error responses Return only the exception message to clients; log full traceback server-side via logger.error(..., exc_info=True). Prevents disclosure of internal paths, library versions, and code structure (CWE-209). --- backend/app/api/simulation.py | 155 ++++++++++++++-------------------- 1 file changed, 62 insertions(+), 93 deletions(-) diff --git a/backend/app/api/simulation.py b/backend/app/api/simulation.py index aae76788..46e7f610 100644 --- a/backend/app/api/simulation.py +++ b/backend/app/api/simulation.py @@ -4,7 +4,6 @@ Step2: Zep实体读取与过滤、OASIS模拟准备与运行(全程自动化 """ import os -import traceback from contextlib import nullcontext from flask import request, jsonify, send_file @@ -112,11 +111,10 @@ def get_graph_entities(graph_id: str): }) except Exception as e: - logger.error(f"获取图谱实体失败: {str(e)}") + logger.error(f"获取图谱实体失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -145,11 +143,10 @@ def get_entity_detail(graph_id: str, entity_uuid: str): }) except Exception as e: - logger.error(f"获取实体详情失败: {str(e)}") + logger.error(f"获取实体详情失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -182,11 +179,10 @@ def get_entities_by_type(graph_id: str, entity_type: str): }) except Exception as e: - logger.error(f"获取实体失败: {str(e)}") + logger.error(f"获取实体失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -259,11 +255,10 @@ def create_simulation(): }) except Exception as e: - logger.error(f"创建模拟失败: {str(e)}") + logger.error(f"创建模拟失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -632,7 +627,7 @@ def prepare_simulation(): ) except Exception as e: - logger.error(f"准备模拟失败: {str(e)}") + logger.error(f"准备模拟失败: {str(e)}", exc_info=True) task_manager.fail_task(task_id, str(e)) # 更新模拟状态为失败 @@ -666,11 +661,10 @@ def prepare_simulation(): }), 404 except Exception as e: - logger.error(f"启动准备任务失败: {str(e)}") + logger.error(f"启动准备任务失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -780,7 +774,7 @@ def get_prepare_status(): }) except Exception as e: - logger.error(f"查询任务状态失败: {str(e)}") + logger.error(f"查询任务状态失败: {str(e)}", exc_info=True) return jsonify({ "success": False, "error": str(e) @@ -812,11 +806,10 @@ def get_simulation(simulation_id: str): }) except Exception as e: - logger.error(f"获取模拟状态失败: {str(e)}") + logger.error(f"获取模拟状态失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -841,11 +834,10 @@ def list_simulations(): }) except Exception as e: - logger.error(f"列出模拟失败: {str(e)}") + logger.error(f"列出模拟失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -1014,11 +1006,10 @@ def get_simulation_history(): }) except Exception as e: - logger.error(f"获取历史模拟失败: {str(e)}") + logger.error(f"获取历史模拟失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -1052,11 +1043,10 @@ def get_simulation_profiles(simulation_id: str): }), 404 except Exception as e: - logger.error(f"获取Profile失败: {str(e)}") + logger.error(f"获取Profile失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -1167,11 +1157,10 @@ def get_simulation_profiles_realtime(simulation_id: str): }) except Exception as e: - logger.error(f"实时获取Profile失败: {str(e)}") + logger.error(f"实时获取Profile失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -1297,11 +1286,10 @@ def get_simulation_config_realtime(simulation_id: str): }) except Exception as e: - logger.error(f"实时获取Config失败: {str(e)}") + logger.error(f"实时获取Config失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -1333,11 +1321,10 @@ def get_simulation_config(simulation_id: str): }) except Exception as e: - logger.error(f"获取配置失败: {str(e)}") + logger.error(f"获取配置失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -1362,11 +1349,10 @@ def download_simulation_config(simulation_id: str): ) except Exception as e: - logger.error(f"下载配置失败: {str(e)}") + logger.error(f"下载配置失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -1414,11 +1400,10 @@ def download_simulation_script(script_name: str): ) except Exception as e: - logger.error(f"下载脚本失败: {str(e)}") + logger.error(f"下载脚本失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -1488,11 +1473,10 @@ def generate_profiles(): }) except Exception as e: - logger.error(f"生成Profile失败: {str(e)}") + logger.error(f"生成Profile失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -1777,11 +1761,10 @@ def start_simulation(): }), 400 except Exception as e: - logger.error(f"启动模拟失败: {str(e)}") + logger.error(f"启动模拟失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -1844,7 +1827,7 @@ def stop_simulation(): }), 400 except Exception as e: - logger.error(f"停止模拟失败: {str(e)}") + logger.error(f"停止模拟失败: {str(e)}", exc_info=True) simulation_id = (request.get_json(silent=True) or {}).get('simulation_id') if simulation_id: manager = SimulationManager() @@ -1855,8 +1838,7 @@ def stop_simulation(): manager._save_simulation_state(state) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -1912,11 +1894,10 @@ def get_run_status(simulation_id: str): }) except Exception as e: - logger.error(f"获取运行状态失败: {str(e)}") + logger.error(f"获取运行状态失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -2013,11 +1994,10 @@ def get_run_status_detail(simulation_id: str): }) except Exception as e: - logger.error(f"获取详细状态失败: {str(e)}") + logger.error(f"获取详细状态失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -2067,11 +2047,10 @@ def get_simulation_actions(simulation_id: str): }) except Exception as e: - logger.error(f"获取动作历史失败: {str(e)}") + logger.error(f"获取动作历史失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -2107,11 +2086,10 @@ def get_simulation_timeline(simulation_id: str): }) except Exception as e: - logger.error(f"获取时间线失败: {str(e)}") + logger.error(f"获取时间线失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -2134,11 +2112,10 @@ def get_agent_stats(simulation_id: str): }) except Exception as e: - logger.error(f"获取Agent统计失败: {str(e)}") + logger.error(f"获取Agent统计失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -2214,11 +2191,10 @@ def get_simulation_posts(simulation_id: str): }) except Exception as e: - logger.error(f"获取帖子失败: {str(e)}") + logger.error(f"获取帖子失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -2291,11 +2267,10 @@ def get_simulation_comments(simulation_id: str): }) except Exception as e: - logger.error(f"获取评论失败: {str(e)}") + logger.error(f"获取评论失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -2422,11 +2397,10 @@ def interview_agent(): }), 504 except Exception as e: - logger.error(f"Interview失败: {str(e)}") + logger.error(f"Interview失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -2560,11 +2534,10 @@ def interview_agents_batch(): }), 504 except Exception as e: - logger.error(f"批量Interview失败: {str(e)}") + logger.error(f"批量Interview失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -2663,11 +2636,10 @@ def interview_all_agents(): }), 504 except Exception as e: - logger.error(f"全局Interview失败: {str(e)}") + logger.error(f"全局Interview失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -2735,11 +2707,10 @@ def get_interview_history(): }) except Exception as e: - logger.error(f"获取Interview历史失败: {str(e)}") + logger.error(f"获取Interview历史失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -2800,11 +2771,10 @@ def get_env_status(): }) except Exception as e: - logger.error(f"获取环境状态失败: {str(e)}") + logger.error(f"获取环境状态失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500 @@ -2870,9 +2840,8 @@ def close_simulation_env(): }), 400 except Exception as e: - logger.error(f"关闭环境失败: {str(e)}") + logger.error(f"关闭环境失败: {str(e)}", exc_info=True) return jsonify({ "success": False, - "error": str(e), - "traceback": traceback.format_exc() + "error": str(e) }), 500