From 43c191931881c91bf8b6b223f3edcf0d775e981b Mon Sep 17 00:00:00 2001 From: aitbc Date: Tue, 5 May 2026 17:23:32 +0200 Subject: [PATCH] fix: remove stack-trace exposure in exception handlers - Add logging to multi_modal_rl.py and log errors instead of exposing exception details - Log NetworkError exceptions in blockchain.py instead of exposing exception details - Replace str(e) with generic error messages in consensus.py exception handlers - Replace str(e) with generic error messages in users.py exception handlers - Fixes py/stack-trace-exposure security alerts --- .../src/app/routers/consensus.py | 16 ++++----- .../src/app/routers/users.py | 4 +-- .../src/app/routers/blockchain.py | 24 ++++++++----- .../src/app/routers/multi_modal_rl.py | 36 +++++++++++++------ 4 files changed, 51 insertions(+), 29 deletions(-) diff --git a/apps/agent-coordinator/src/app/routers/consensus.py b/apps/agent-coordinator/src/app/routers/consensus.py index 8342250e..f7e1db5e 100644 --- a/apps/agent-coordinator/src/app/routers/consensus.py +++ b/apps/agent-coordinator/src/app/routers/consensus.py @@ -32,7 +32,7 @@ async def register_consensus_node(node_data: Dict[str, Any]): return result except Exception as e: logger.error(f"Error registering consensus node: {e}") - raise HTTPException(status_code=500, detail=str(e)) + raise HTTPException(status_code=500, detail="Failed to register consensus node") @router.post("/consensus/proposal/create") async def create_consensus_proposal(proposal_data: Dict[str, Any]): @@ -42,7 +42,7 @@ async def create_consensus_proposal(proposal_data: Dict[str, Any]): return result except Exception as e: logger.error(f"Error creating consensus proposal: {e}") - raise HTTPException(status_code=500, detail=str(e)) + raise HTTPException(status_code=500, detail="Failed to create consensus proposal") @router.post("/consensus/proposal/{proposal_id}/vote") async def cast_consensus_vote(proposal_id: str, node_id: str, vote: bool): @@ -52,7 +52,7 @@ async def cast_consensus_vote(proposal_id: str, node_id: str, vote: bool): return result except Exception as e: logger.error(f"Error casting consensus vote: {e}") - raise HTTPException(status_code=500, detail=str(e)) + raise HTTPException(status_code=500, detail="Failed to cast consensus vote") @router.get("/consensus/proposal/{proposal_id}") async def get_proposal_status(proposal_id: str): @@ -62,7 +62,7 @@ async def get_proposal_status(proposal_id: str): return result except Exception as e: logger.error(f"Error getting proposal status: {e}") - raise HTTPException(status_code=500, detail=str(e)) + raise HTTPException(status_code=500, detail="Failed to get proposal status") @router.put("/consensus/algorithm") async def set_consensus_algorithm(algorithm: str = Query(..., description="Consensus algorithm")): @@ -72,7 +72,7 @@ async def set_consensus_algorithm(algorithm: str = Query(..., description="Conse return result except Exception as e: logger.error(f"Error setting consensus algorithm: {e}") - raise HTTPException(status_code=500, detail=str(e)) + raise HTTPException(status_code=500, detail="Failed to set consensus algorithm") @router.get("/consensus/statistics") async def get_consensus_statistics(): @@ -82,7 +82,7 @@ async def get_consensus_statistics(): return result except Exception as e: logger.error(f"Error getting consensus statistics: {e}") - raise HTTPException(status_code=500, detail=str(e)) + raise HTTPException(status_code=500, detail="Failed to get consensus statistics") @router.put("/consensus/node/{node_id}/status") async def update_node_status(node_id: str, is_active: bool): @@ -92,7 +92,7 @@ async def update_node_status(node_id: str, is_active: bool): return result except Exception as e: logger.error(f"Error updating node status: {e}") - raise HTTPException(status_code=500, detail=str(e)) + raise HTTPException(status_code=500, detail="Failed to update node status") # Advanced features status endpoint @router.get("/advanced-features/status") @@ -130,4 +130,4 @@ async def get_advanced_features_status(): } except Exception as e: logger.error(f"Error getting advanced features status: {e}") - raise HTTPException(status_code=500, detail=str(e)) + raise HTTPException(status_code=500, detail="Failed to get advanced features status") diff --git a/apps/agent-coordinator/src/app/routers/users.py b/apps/agent-coordinator/src/app/routers/users.py index c006b1fb..b828b228 100644 --- a/apps/agent-coordinator/src/app/routers/users.py +++ b/apps/agent-coordinator/src/app/routers/users.py @@ -190,7 +190,7 @@ async def get_role_permissions( raise except Exception as e: logger.error(f"Error getting role permissions: {e}") - raise HTTPException(status_code=500, detail=str(e)) + raise HTTPException(status_code=500, detail="Failed to get role permissions") @router.get("/auth/stats") async def get_permission_stats(current_user: Dict[str, Any] = Depends(get_current_user)): @@ -208,7 +208,7 @@ async def get_permission_stats(current_user: Dict[str, Any] = Depends(get_curren raise except Exception as e: logger.error(f"Error getting permission stats: {e}") - raise HTTPException(status_code=500, detail=str(e)) + raise HTTPException(status_code=500, detail="Failed to get permission stats") # Protected endpoint example @router.get("/protected/admin") diff --git a/apps/coordinator-api/src/app/routers/blockchain.py b/apps/coordinator-api/src/app/routers/blockchain.py index 1eafc684..a9793a32 100755 --- a/apps/coordinator-api/src/app/routers/blockchain.py +++ b/apps/coordinator-api/src/app/routers/blockchain.py @@ -58,7 +58,8 @@ async def blockchain_sync_status() -> dict[str, Any]: else: return {"status": "synced", "block": response.get("current_block", 0)} except NetworkError as e: - return {"status": "error", "error": f"RPC connection failed: {e}"} + logger.error(f"RPC connection failed: {e}") + return {"status": "error", "error": "RPC connection failed"} except Exception as e: return {"status": "error", "error": "Failed to get sync status"} @@ -73,7 +74,8 @@ async def get_block(height: int) -> dict[str, Any]: response = client.get(f"{rpc_url}/rpc/blocks/{height}") return response except NetworkError as e: - return {"status": "error", "error": f"RPC connection failed: {e}"} + logger.error(f"RPC connection failed: {e}") + return {"status": "error", "error": "RPC connection failed"} @router.get("/blocks/hash/{block_hash}") @@ -87,7 +89,8 @@ async def get_block_by_hash(block_hash: str) -> dict[str, Any]: response = client.get(f"{rpc_url}/rpc/blocks/hash/{block_hash}") return response except NetworkError as e: - return {"status": "error", "error": f"RPC connection failed: {e}"} + logger.error(f"RPC connection failed: {e}") + return {"status": "error", "error": "RPC connection failed"} @router.get("/transactions/{tx_hash}") @@ -101,7 +104,8 @@ async def get_transaction(tx_hash: str) -> dict[str, Any]: response = client.get(f"{rpc_url}/rpc/transactions/{tx_hash}") return response except NetworkError as e: - return {"status": "error", "error": f"RPC connection failed: {e}"} + logger.error(f"RPC connection failed: {e}") + return {"status": "error", "error": "RPC connection failed"} @router.get("/accounts/{address}") @@ -115,7 +119,8 @@ async def get_account(address: str) -> dict[str, Any]: response = client.get(f"{rpc_url}/rpc/accounts/{address}") return response except NetworkError as e: - return {"status": "error", "error": f"RPC connection failed: {e}"} + logger.error(f"RPC connection failed: {e}") + return {"status": "error", "error": "RPC connection failed"} @router.get("/validators") @@ -134,7 +139,8 @@ async def get_validators() -> dict[str, Any]: "total": 1 } except NetworkError as e: - return {"status": "error", "error": f"RPC connection failed: {e}"} + logger.error(f"RPC connection failed: {e}") + return {"status": "error", "error": "RPC connection failed"} @router.get("/supply") @@ -155,7 +161,8 @@ async def get_supply() -> dict[str, Any]: "unit": "AIT" } except NetworkError as e: - return {"status": "error", "error": f"RPC connection failed: {e}"} + logger.error(f"RPC connection failed: {e}") + return {"status": "error", "error": "RPC connection failed"} @router.get("/state/dump") @@ -173,4 +180,5 @@ async def get_state_dump() -> dict[str, Any]: "timestamp": response.get("timestamp", "") } except NetworkError as e: - return {"status": "error", "error": f"RPC connection failed: {e}"} + logger.error(f"RPC connection failed: {e}") + return {"status": "error", "error": "RPC connection failed"} diff --git a/apps/coordinator-api/src/app/routers/multi_modal_rl.py b/apps/coordinator-api/src/app/routers/multi_modal_rl.py index a487979c..cc709fe5 100644 --- a/apps/coordinator-api/src/app/routers/multi_modal_rl.py +++ b/apps/coordinator-api/src/app/routers/multi_modal_rl.py @@ -3,6 +3,7 @@ Multi-modal RL Router Handles multi-modal reinforcement learning endpoints by proxying to AI service """ +import logging from typing import Any from fastapi import APIRouter @@ -10,6 +11,8 @@ from pydantic import BaseModel from aitbc import AITBCHTTPClient, NetworkError +logger = logging.getLogger(__name__) + router = APIRouter(prefix="/multi-modal-rl", tags=["multi-modal-rl"]) @@ -45,9 +48,11 @@ async def submit_job(req: JobCreate, client_id: str = "default_client") -> dict[ response = client.post(f"{ai_url}/jobs", json=job_data) return response except NetworkError as e: - return {"error": f"AI service connection failed: {e}"} + logger.error(f"AI service connection failed: {e}") + return {"error": "AI service connection failed"} except Exception as e: - return {"error": f"Failed to submit job: {e}"} + logger.error(f"Failed to submit job: {e}") + return {"error": "Failed to submit job"} @router.get("/jobs/{job_id}") @@ -59,9 +64,11 @@ async def get_job(job_id: str, client_id: str = "default_client") -> dict[str, A response = client.get(f"{ai_url}/jobs/{job_id}", params={"client_id": client_id}) return response except NetworkError as e: - return {"error": f"AI service connection failed: {e}"} + logger.error(f"AI service connection failed: {e}") + return {"error": "AI service connection failed"} except Exception as e: - return {"error": f"Failed to get job: {e}"} + logger.error(f"Failed to get job: {e}") + return {"error": "Failed to get job"} @router.get("/jobs/{job_id}/result") @@ -73,9 +80,11 @@ async def get_job_result(job_id: str, client_id: str = "default_client") -> dict response = client.get(f"{ai_url}/jobs/{job_id}/result", params={"client_id": client_id}) return response except NetworkError as e: - return {"error": f"AI service connection failed: {e}"} + logger.error(f"AI service connection failed: {e}") + return {"error": "AI service connection failed"} except Exception as e: - return {"error": f"Failed to get job result: {e}"} + logger.error(f"Failed to get job result: {e}") + return {"error": "Failed to get job result"} @router.post("/jobs/{job_id}/cancel") @@ -87,9 +96,11 @@ async def cancel_job(job_id: str, client_id: str = "default_client") -> dict[str response = client.post(f"{ai_url}/jobs/{job_id}/cancel", params={"client_id": client_id}) return response except NetworkError as e: - return {"error": f"AI service connection failed: {e}"} + logger.error(f"AI service connection failed: {e}") + return {"error": "AI service connection failed"} except Exception as e: - return {"error": f"Failed to cancel job: {e}"} + logger.error(f"Failed to cancel job: {e}") + return {"error": "Failed to cancel job"} @router.get("/jobs") @@ -104,9 +115,11 @@ async def list_jobs(client_id: str = "default_client", limit: int = 10, state: s response = client.get(f"{ai_url}/jobs", params=params) return response except NetworkError as e: - return {"error": f"AI service connection failed: {e}"} + logger.error(f"AI service connection failed: {e}") + return {"error": "AI service connection failed"} except Exception as e: - return {"error": f"Failed to list jobs: {e}"} + logger.error(f"Failed to list jobs: {e}") + return {"error": "Failed to list jobs"} @router.get("/health") @@ -128,7 +141,8 @@ async def health() -> dict[str, Any]: "ai_service": "unreachable", "note": "AI service not available on this node" } - except Exception: + except Exception as e: + logger.error(f"AI service check failed: {e}") return { "status": "degraded", "router": "multi-modal-rl",