diff --git a/application/api/connector/routes.py b/application/api/connector/routes.py index 1a4e80bf..91fc3f0b 100644 --- a/application/api/connector/routes.py +++ b/application/api/connector/routes.py @@ -487,11 +487,15 @@ class ConnectorCallbackStatus(Resource): session_token = request.args.get('session_token', '') user_email = html.escape(request.args.get('user_email', '')) - # Use json.dumps for safe JavaScript string embedding - js_status = json.dumps(status) - js_session_token = json.dumps(session_token) - js_user_email = json.dumps(user_email) - js_provider_type = json.dumps(provider_raw) + def safe_js_string(value: str) -> str: + """Safely encode a string for embedding in inline JavaScript.""" + js_encoded = json.dumps(value) + return js_encoded.replace(' diff --git a/application/api/user/agents/routes.py b/application/api/user/agents/routes.py index bcf68b56..a71f8fc8 100644 --- a/application/api/user/agents/routes.py +++ b/application/api/user/agents/routes.py @@ -307,9 +307,10 @@ class CreateAgent(Resource): 400, ) except Exception as e: + current_app.logger.error(f"Invalid JSON schema: {e}") return make_response( jsonify( - {"success": False, "message": f"Invalid JSON schema: {str(e)}"} + {"success": False, "message": "Invalid JSON schema format"} ), 400, ) diff --git a/application/api/user/agents/sharing.py b/application/api/user/agents/sharing.py index ca9044e4..034fc75d 100644 --- a/application/api/user/agents/sharing.py +++ b/application/api/user/agents/sharing.py @@ -255,8 +255,8 @@ class ShareAgent(Resource): {"$unset": {"shared_metadata": ""}}, ) except Exception as err: - current_app.logger.error(f"Error sharing/unsharing agent: {err}") - return make_response(jsonify({"success": False, "error": str(err)}), 400) + current_app.logger.error(f"Error sharing/unsharing agent: {err}", exc_info=True) + return make_response(jsonify({"success": False, "error": "Failed to update agent sharing status"}), 400) shared_token = shared_token if shared else None return make_response( jsonify({"success": True, "shared_token": shared_token}), 200 diff --git a/application/api/user/attachments/routes.py b/application/api/user/attachments/routes.py index 3935821d..32c4cdca 100644 --- a/application/api/user/attachments/routes.py +++ b/application/api/user/attachments/routes.py @@ -99,11 +99,8 @@ class StoreAttachment(Resource): }) if not tasks: - error_msg = "No valid files to upload" - if errors: - error_msg += f". Errors: {errors}" return make_response( - jsonify({"status": "error", "message": error_msg, "errors": errors}), + jsonify({"status": "error", "message": "No valid files to upload"}), 400, ) @@ -135,7 +132,7 @@ class StoreAttachment(Resource): ) except Exception as err: current_app.logger.error(f"Error storing attachment: {err}", exc_info=True) - return make_response(jsonify({"success": False, "error": str(err)}), 400) + return make_response(jsonify({"success": False, "error": "Failed to store attachment"}), 400) @attachments_ns.route("/images/") diff --git a/application/api/user/sources/upload.py b/application/api/user/sources/upload.py index 6c163da4..801e5b44 100644 --- a/application/api/user/sources/upload.py +++ b/application/api/user/sources/upload.py @@ -579,8 +579,9 @@ class TaskStatus(Resource): ): task_meta = str(task_meta) # Convert to a string representation except ConnectionError as err: + current_app.logger.error(f"Connection error getting task status: {err}") return make_response( - jsonify({"success": False, "message": str(err)}), 503 + jsonify({"success": False, "message": "Service unavailable"}), 503 ) except Exception as err: current_app.logger.error(f"Error getting task status: {err}", exc_info=True) diff --git a/application/api/user/tools/mcp.py b/application/api/user/tools/mcp.py index 615ada5e..f34115bb 100644 --- a/application/api/user/tools/mcp.py +++ b/application/api/user/tools/mcp.py @@ -1,7 +1,7 @@ """Tool management MCP server integration.""" import json -from email.quoprimime import unquote +from urllib.parse import unquote, urlencode from bson.objectid import ObjectId from flask import current_app, jsonify, make_response, redirect, request @@ -64,6 +64,11 @@ class TestMCPServerConfig(Resource): mcp_tool = MCPTool(config=test_config, user_id=user) result = mcp_tool.test_connection() + # Sanitize the response to avoid exposing internal error details + if not result.get("success") and "message" in result: + current_app.logger.error(f"MCP connection test failed: {result.get('message')}") + result["message"] = "Connection test failed" + return make_response(jsonify(result), 200) except Exception as e: current_app.logger.error(f"Error testing MCP server: {e}", exc_info=True) @@ -263,9 +268,12 @@ class MCPOAuthCallback(Resource): error = request.args.get("error") if error: - return redirect( - f"/api/connectors/callback-status?status=error&message=OAuth+error:+{error}.+Please+try+again+and+make+sure+to+grant+all+requested+permissions,+including+offline+access.&provider=mcp_tool" - ) + params = { + "status": "error", + "message": f"OAuth error: {error}. Please try again and make sure to grant all requested permissions, including offline access.", + "provider": "mcp_tool" + } + return redirect(f"/api/connectors/callback-status?{urlencode(params)}") if not code or not state: return redirect( "/api/connectors/callback-status?status=error&message=Authorization+code+or+state+not+provided.+Please+complete+the+authorization+process+and+make+sure+to+grant+offline+access.&provider=mcp_tool" diff --git a/application/api/user/tools/routes.py b/application/api/user/tools/routes.py index 1503ef7e..384e8b8a 100644 --- a/application/api/user/tools/routes.py +++ b/application/api/user/tools/routes.py @@ -462,10 +462,8 @@ class ParseSpec(Resource): 200, ) except ValueError as e: - error_msg = str(e) - current_app.logger.error(f"Spec validation error: {error_msg}") - return make_response(jsonify({"success": False, "error": error_msg}), 400) + current_app.logger.error(f"Spec validation error: {e}") + return make_response(jsonify({"success": False, "error": "Invalid specification format"}), 400) except Exception as err: - error_msg = str(err) - current_app.logger.error(f"Error parsing spec: {error_msg}", exc_info=True) - return make_response(jsonify({"success": False, "error": error_msg}), 500) + current_app.logger.error(f"Error parsing spec: {err}", exc_info=True) + return make_response(jsonify({"success": False, "error": "Failed to parse specification"}), 500)