Mostly safe — a couple of notes worth reading.
Scanned 6/15/2026, 10:01:26 PM·Cached result·Fast Scan·48 rules·How we decide ↗
AIVSS Score
Low
Severity Breakdown
0
critical
0
high
61
medium
18
low
MCP Server Information
Findings
This package scores 81/100 on safety with a B-grade, but carries moderate risk due to 61 medium-severity findings concentrated in verbose error handling and readiness issues. The 49 verbose error findings could expose sensitive information in logs, while 18 readiness issues suggest incomplete implementation that may cause unexpected behavior in production. The AIVSS score of 4.0/10 indicates notable security concerns that warrant review before deployment, particularly around error message handling and resource exhaustion vulnerabilities.
No known CVEs found for this package or its dependencies.
Scan Details
Want deeper analysis?
Fast scan found 79 findings using rule-based analysis. Upgrade for LLM consensus across 5 judges, AI-generated remediation, and cross-file taint analysis.
Building your own MCP server?
Same rules, same LLM judges, same grade. Private scans stay isolated to your account and never appear in the public registry. Required for code your team hasn’t shipped yet.
Showing 1–30 of 79 findings
79 findings
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 834 | logger.error(f"Error downloading Sketchfab model: {str(e)}") |
| 835 | import traceback |
| 836 | logger.error(traceback.format_exc()) |
| 837 | return f"Error downloading Sketchfab model: {str(e)}" |
| 838 | |
| 839 | def _process_bbox(original_bbox: list[float] | list[int] | None) -> list[int] | None: |
| 840 | if original_bbox is None: |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 1683 | except requests.exceptions.Timeout: |
| 1684 | return {"error": "Request timed out. Check your internet connection."} |
| 1685 | except json.JSONDecodeError as e: |
| 1686 | return {"error": f"Invalid JSON response from Sketchfab API: {str(e)}"} |
| 1687 | except Exception as e: |
| 1688 | import traceback |
| 1689 | traceback.print_exc() |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 387 | return f"Code executed successfully: {result.get('result', '')}" |
| 388 | except Exception as e: |
| 389 | logger.error(f"Error executing code: {str(e)}") |
| 390 | return f"Error executing code: {str(e)}" |
| 391 | |
| 392 | @mcp.tool() |
| 393 | @telemetry_tool("get_polyhaven_categories") |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 1473 | # Clean up the file if there's an error |
| 1474 | temp_file.close() |
| 1475 | os.unlink(temp_file.name) |
| 1476 | return {"succeed": False, "error": str(e)} |
| 1477 | |
| 1478 | break |
| 1479 | else: |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 1687 | except Exception as e: |
| 1688 | import traceback |
| 1689 | traceback.print_exc() |
| 1690 | return {"error": str(e)} |
| 1691 | |
| 1692 | def get_sketchfab_model_preview(self, uid): |
| 1693 | """Get thumbnail preview image of a Sketchfab model by its UID""" |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 1500 | "succeed": True, **result |
| 1501 | } |
| 1502 | except Exception as e: |
| 1503 | return {"succeed": False, "error": str(e)} |
| 1504 | |
| 1505 | def import_generated_asset_fal_ai(self, request_id: str, name: str): |
| 1506 | """Fetch the generated asset, import into blender""" |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 421 | return formatted_output |
| 422 | except Exception as e: |
| 423 | logger.error(f"Error getting Polyhaven categories: {str(e)}") |
| 424 | return f"Error getting Polyhaven categories: {str(e)}" |
| 425 | |
| 426 | @mcp.tool() |
| 427 | @telemetry_tool("search_polyhaven_assets") |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 2255 | image_base64 = base64.b64encode(f.read()).decode("ascii") |
| 2256 | data["image"] = image_base64 |
| 2257 | except Exception as e: |
| 2258 | return {"error": f"Image encoding failed: {str(e)}"} |
| 2259 | |
| 2260 | response = requests.post( |
| 2261 | f"{base_url}/generate", |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 1094 | return result |
| 1095 | except Exception as e: |
| 1096 | logger.error(f"Error generating Hunyuan3D task: {str(e)}") |
| 1097 | return f"Error generating Hunyuan3D task: {str(e)}" |
| 1098 | |
| 1099 | @mcp.tool() |
| 1100 | @rich_telemetry_tool("import_generated_asset_hunyuan") |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 2247 | image_base64 = base64.b64encode(resImg.content).decode("ascii") |
| 2248 | data["image"] = image_base64 |
| 2249 | except Exception as e: |
| 2250 | return {"error": f"Failed to download or encode image: {str(e)}"} |
| 2251 | else: |
| 2252 | try: |
| 2253 | # Convert to Base64 format |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 2401 | return {"succeed": True, **result} |
| 2402 | except Exception as e: |
| 2403 | return {"succeed": False, "error": str(e)} |
| 2404 | finally: |
| 2405 | # Clean up temporary zip and obj, save texture and mtl |
| 2406 | try: |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 719 | logger.error(f"Error searching Sketchfab models: {str(e)}") |
| 720 | import traceback |
| 721 | logger.error(traceback.format_exc()) |
| 722 | return f"Error searching Sketchfab models: {str(e)}" |
| 723 | |
| 724 | @mcp.tool() |
| 725 | @telemetry_tool("download_sketchfab_model") |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 788 | } |
| 789 | |
| 790 | except Exception as e: |
| 791 | return {"error": f"Failed to process textures: {str(e)}"} |
| 792 | |
| 793 | elif asset_type == "models": |
| 794 | # For models, prefer glTF format if available |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 1561 | "succeed": True, **result |
| 1562 | } |
| 1563 | except Exception as e: |
| 1564 | return {"succeed": False, "error": str(e)} |
| 1565 | #endregion |
| 1566 | |
| 1567 | #region Sketchfab API |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 2207 | "error": f"API request failed with status {response.status_code}: {response}" |
| 2208 | } |
| 2209 | except Exception as e: |
| 2210 | return {"error": str(e)} |
| 2211 | |
| 2212 | def create_hunyuan_job_local_site( |
| 2213 | self, |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 2334 | "error": f"API request failed with status {response.status_code}: {response}" |
| 2335 | } |
| 2336 | except Exception as e: |
| 2337 | return {"error": str(e)} |
| 2338 | |
| 2339 | def import_generated_asset_hunyuan(self, *args, **kwargs): |
| 2340 | return self.import_generated_asset_hunyuan_ai(*args, **kwargs) |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 519 | else: |
| 520 | return {"error": f"API request failed with status code {response.status_code}"} |
| 521 | except Exception as e: |
| 522 | return {"error": str(e)} |
| 523 | |
| 524 | def search_polyhaven_assets(self, asset_type=None, categories=None): |
| 525 | """Search for assets from Polyhaven with optional filtering""" |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 2190 | image_base64 = base64.b64encode(f.read()).decode("ascii") |
| 2191 | data["ImageBase64"] = image_base64 |
| 2192 | except Exception as e: |
| 2193 | return {"error": f"Image encoding failed: {str(e)}"} |
| 2194 | |
| 2195 | # Get signed headers |
| 2196 | headers, endpoint = self.get_tencent_cloud_sign_headers("POST", "/", headParams, data, service, region, secret_id, secret_key) |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 486 | } |
| 487 | |
| 488 | except Exception as e: |
| 489 | return {"error": str(e)} |
| 490 | |
| 491 | def execute_code(self, code): |
| 492 | """Execute arbitrary Blender Python code""" |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 643 | return message |
| 644 | except Exception as e: |
| 645 | logger.error(f"Error checking Sketchfab status: {str(e)}") |
| 646 | return f"Error checking Sketchfab status: {str(e)}" |
| 647 | |
| 648 | @mcp.tool() |
| 649 | @telemetry_tool("search_sketchfab_models") |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 473 | return formatted_output |
| 474 | except Exception as e: |
| 475 | logger.error(f"Error searching Polyhaven assets: {str(e)}") |
| 476 | return f"Error searching Polyhaven assets: {str(e)}" |
| 477 | |
| 478 | @mcp.tool() |
| 479 | @rich_telemetry_tool("download_polyhaven_asset") |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 935 | return json.dumps(result) |
| 936 | except Exception as e: |
| 937 | logger.error(f"Error generating Hyper3D task: {str(e)}") |
| 938 | return f"Error generating Hyper3D task: {str(e)}" |
| 939 | |
| 940 | @mcp.tool() |
| 941 | @telemetry_tool("poll_rodin_job_status") |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 1313 | data = response.json() |
| 1314 | return data |
| 1315 | except Exception as e: |
| 1316 | return {"error": str(e)} |
| 1317 | |
| 1318 | def poll_rodin_job_status(self, *args, **kwargs): |
| 1319 | match bpy.context.scene.blendermcp_hyper3d_mode: |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 1281 | data = response.json() |
| 1282 | return data |
| 1283 | except Exception as e: |
| 1284 | return {"error": str(e)} |
| 1285 | |
| 1286 | def create_rodin_job_fal_ai( |
| 1287 | self, |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 288 | return json.dumps(result, indent=2) |
| 289 | except Exception as e: |
| 290 | logger.error(f"Error getting object info from Blender: {str(e)}") |
| 291 | return f"Error getting object info: {str(e)}" |
| 292 | |
| 293 | @mcp.tool() |
| 294 | def get_viewport_screenshot(ctx: Context, max_size: int = 1000, user_prompt: str = "") -> Image: |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 651 | "image_name": env_tex.image.name |
| 652 | } |
| 653 | except Exception as e: |
| 654 | return {"error": f"Failed to set up HDRI in Blender: {str(e)}"} |
| 655 | else: |
| 656 | return {"error": f"Requested resolution or format not available for this HDRI"} |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 861 | "imported_objects": imported_objects |
| 862 | } |
| 863 | except Exception as e: |
| 864 | return {"error": f"Failed to import model: {str(e)}"} |
| 865 | finally: |
| 866 | # Clean up temporary directory |
| 867 | with suppress(Exception): |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 1177 | except Exception as e: |
| 1178 | print(f"Error in set_texture: {str(e)}") |
| 1179 | traceback.print_exc() |
| 1180 | return {"error": f"Failed to apply texture: {str(e)}"} |
| 1181 | |
| 1182 | def get_telemetry_consent(self): |
| 1183 | """Get the current telemetry consent status""" |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 873 | return {"error": f"Unsupported asset type: {asset_type}"} |
| 874 | |
| 875 | except Exception as e: |
| 876 | return {"error": f"Failed to download asset: {str(e)}"} |
| 877 | |
| 878 | def set_texture(self, object_name, texture_id): |
| 879 | """Apply a previously downloaded Polyhaven texture to an object by creating a new material""" |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 1773 | except Exception as e: |
| 1774 | import traceback |
| 1775 | traceback.print_exc() |
| 1776 | return {"error": f"Failed to get model preview: {str(e)}"} |
| 1777 | |
| 1778 | def download_sketchfab_model(self, uid, normalize_size=False, target_size=1.0): |
| 1779 | """Download a model from Sketchfab by its UID |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 605 | return message |
| 606 | except Exception as e: |
| 607 | logger.error(f"Error checking PolyHaven status: {str(e)}") |
| 608 | return f"Error checking PolyHaven status: {str(e)}" |
| 609 | |
| 610 | @mcp.tool() |
| 611 | @telemetry_tool("get_hyper3d_status") |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 1028 | return message |
| 1029 | except Exception as e: |
| 1030 | logger.error(f"Error checking Hunyuan3D status: {str(e)}") |
| 1031 | return f"Error checking Hunyuan3D status: {str(e)}" |
| 1032 | |
| 1033 | @mcp.tool() |
| 1034 | @rich_telemetry_tool("generate_hunyuan3d_model") |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 527 | return f"Failed to download asset: {result.get('message', 'Unknown error')}" |
| 528 | except Exception as e: |
| 529 | logger.error(f"Error downloading Polyhaven asset: {str(e)}") |
| 530 | return f"Error downloading Polyhaven asset: {str(e)}" |
| 531 | |
| 532 | @mcp.tool() |
| 533 | @telemetry_tool("set_texture") |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 879 | return json.dumps(result) |
| 880 | except Exception as e: |
| 881 | logger.error(f"Error generating Hyper3D task: {str(e)}") |
| 882 | return f"Error generating Hyper3D task: {str(e)}" |
| 883 | |
| 884 | @mcp.tool() |
| 885 | @rich_telemetry_tool("generate_hyper3d_model_via_images") |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 261 | except Exception as e: |
| 262 | print(f"Error executing command: {str(e)}") |
| 263 | traceback.print_exc() |
| 264 | return {"status": "error", "message": str(e)} |
| 265 | |
| 266 | def _execute_command_internal(self, command): |
| 267 | """Internal command execution with proper context""" |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 2286 | } |
| 2287 | except Exception as e: |
| 2288 | print(f"An error occurred: {e}") |
| 2289 | return {"error": str(e)} |
| 2290 | |
| 2291 | |
| 2292 | def poll_hunyuan_job_status(self, *args, **kwargs): |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 370 | except Exception as e: |
| 371 | print(f"Error in get_scene_info: {str(e)}") |
| 372 | traceback.print_exc() |
| 373 | return {"error": str(e)} |
| 374 | |
| 375 | @staticmethod |
| 376 | def _get_aabb(obj): |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 332 | except Exception as e: |
| 333 | print(f"Error in handler: {str(e)}") |
| 334 | traceback.print_exc() |
| 335 | return {"status": "error", "message": str(e)} |
| 336 | else: |
| 337 | return {"status": "error", "message": f"Unknown command type: {cmd_type}"} |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 979 | return result |
| 980 | except Exception as e: |
| 981 | logger.error(f"Error generating Hyper3D task: {str(e)}") |
| 982 | return f"Error generating Hyper3D task: {str(e)}" |
| 983 | |
| 984 | @mcp.tool() |
| 985 | @rich_telemetry_tool("import_generated_asset") |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 550 | else: |
| 551 | return {"error": f"API request failed with status code {response.status_code}"} |
| 552 | except Exception as e: |
| 553 | return {"error": str(e)} |
| 554 | |
| 555 | def download_polyhaven_asset(self, asset_id, asset_type, resolution="1k", file_format=None): |
| 556 | try: |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 1992 | except requests.exceptions.Timeout: |
| 1993 | return {"error": "Request timed out. Check your internet connection and try again with a simpler model."} |
| 1994 | except json.JSONDecodeError as e: |
| 1995 | return {"error": f"Invalid JSON response from Sketchfab API: {str(e)}"} |
| 1996 | except Exception as e: |
| 1997 | import traceback |
| 1998 | traceback.print_exc() |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 624 | return message |
| 625 | except Exception as e: |
| 626 | logger.error(f"Error checking Hyper3D status: {str(e)}") |
| 627 | return f"Error checking Hyper3D status: {str(e)}" |
| 628 | |
| 629 | @mcp.tool() |
| 630 | @telemetry_tool("get_sketchfab_status") |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 1538 | # Clean up the file if there's an error |
| 1539 | temp_file.close() |
| 1540 | os.unlink(temp_file.name) |
| 1541 | return {"succeed": False, "error": str(e)} |
| 1542 | |
| 1543 | try: |
| 1544 | obj = self._clean_imported_glb( |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 1996 | except Exception as e: |
| 1997 | import traceback |
| 1998 | traceback.print_exc() |
| 1999 | return {"error": f"Failed to download model: {str(e)}"} |
| 2000 | #endregion |
| 2001 | |
| 2002 | #region Hunyuan3D |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 1065 | return json.dumps(result) |
| 1066 | except Exception as e: |
| 1067 | logger.error(f"Error generating Hunyuan3D task: {str(e)}") |
| 1068 | return f"Error generating Hunyuan3D task: {str(e)}" |
| 1069 | |
| 1070 | @mcp.tool() |
| 1071 | def poll_hunyuan_job_status( |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 1013 | return result |
| 1014 | except Exception as e: |
| 1015 | logger.error(f"Error generating Hyper3D task: {str(e)}") |
| 1016 | return f"Error generating Hyper3D task: {str(e)}" |
| 1017 | |
| 1018 | @mcp.tool() |
| 1019 | def get_hunyuan3d_status(ctx: Context, user_prompt: str = "") -> str: |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 268 | return json.dumps(result, indent=2) |
| 269 | except Exception as e: |
| 270 | logger.error(f"Error getting scene info from Blender: {str(e)}") |
| 271 | return f"Error getting scene info: {str(e)}" |
| 272 | |
| 273 | @mcp.tool() |
| 274 | @telemetry_tool("get_object_info") |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 586 | return f"Failed to apply texture: {result.get('message', 'Unknown error')}" |
| 587 | except Exception as e: |
| 588 | logger.error(f"Error applying texture: {str(e)}") |
| 589 | return f"Error applying texture: {str(e)}" |
| 590 | |
| 591 | @mcp.tool() |
| 592 | @telemetry_tool("get_polyhaven_status") |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 1123 | return result |
| 1124 | except Exception as e: |
| 1125 | logger.error(f"Error generating Hunyuan3D task: {str(e)}") |
| 1126 | return f"Error generating Hunyuan3D task: {str(e)}" |
| 1127 | |
| 1128 | |
| 1129 | @mcp.prompt() |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 575 | # since Blender can't properly load HDR data directly from memory |
| 576 | with tempfile.NamedTemporaryFile(suffix=f".{file_format}", delete=False) as tmp_file: |
| 577 | # Download the file |
| 578 | response = requests.get(file_url, headers=REQ_HEADERS) |
| 579 | if response.status_code != 200: |
| 580 | return {"error": f"Failed to download HDRI: {response.status_code}"} |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 2355 | try: |
| 2356 | # Download ZIP file |
| 2357 | zip_response = requests.get(zip_file_url, stream=True) |
| 2358 | zip_response.raise_for_status() |
| 2359 | with open(zip_file_path, "wb") as f: |
| 2360 | for chunk in zip_response.iter_content(chunk_size=8192): |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 1524 | try: |
| 1525 | # Download the content |
| 1526 | response = requests.get(data_["model_mesh"]["url"], stream=True) |
| 1527 | response.raise_for_status() # Raise an exception for HTTP errors |
| 1528 | |
| 1529 | # Write the content to the temporary file |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 555 | def download_polyhaven_asset(self, asset_id, asset_type, resolution="1k", file_format=None): |
| 556 | try: |
| 557 | # First get the files information |
| 558 | files_response = requests.get(f"https://api.polyhaven.com/files/{asset_id}", headers=REQ_HEADERS) |
| 559 | if files_response.status_code != 200: |
| 560 | return {"error": f"Failed to get asset files: {files_response.status_code}"} |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 808 | main_file_name = file_url.split("/")[-1] |
| 809 | main_file_path = os.path.join(temp_dir, main_file_name) |
| 810 | |
| 811 | response = requests.get(file_url, headers=REQ_HEADERS) |
| 812 | if response.status_code != 200: |
| 813 | return {"error": f"Failed to download model: {response.status_code}"} |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 671 | # Use NamedTemporaryFile like we do for HDRIs |
| 672 | with tempfile.NamedTemporaryFile(suffix=f".{file_format}", delete=False) as tmp_file: |
| 673 | # Download the file |
| 674 | response = requests.get(file_url, headers=REQ_HEADERS) |
| 675 | if response.status_code == 200: |
| 676 | tmp_file.write(response.content) |
| 677 | tmp_path |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 535 | if categories: |
| 536 | params["categories"] = categories |
| 537 | |
| 538 | response = requests.get(url, params=params, headers=REQ_HEADERS) |
| 539 | if response.status_code == 200: |
| 540 | # Limit the response size to avoid overwhelming Blender |
| 541 | assets = response.json() |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 2242 | if image: |
| 2243 | if re.match(r'^https?://', image, re.IGNORECASE) is not None: |
| 2244 | try: |
| 2245 | resImg = requests.get(image) |
| 2246 | resImg.raise_for_status() |
| 2247 | image_base64 = base64.b64encode(resImg.content).decode("ascii") |
| 2248 | data["image"] = image_base64 |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 1459 | try: |
| 1460 | # Download the content |
| 1461 | response = requests.get(i["url"], stream=True) |
| 1462 | response.raise_for_status() # Raise an exception for HTTP errors |
| 1463 | |
| 1464 | # Write the content to the temporary file |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 826 | os.makedirs(os.path.dirname(include_file_path), exist_ok=True) |
| 827 | |
| 828 | # Download the included file |
| 829 | include_response = requests.get(include_url, headers=REQ_HEADERS) |
| 830 | if include_response.status_code == 200: |
| 831 | with open(include_file_path, "wb") as f: |
| 832 | f.write(include_response.content) |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 513 | if asset_type not in ["hdris", "textures", "models", "all"]: |
| 514 | return {"error": f"Invalid asset type: {asset_type}. Must be one of: hdris, textures, models, all"} |
| 515 | |
| 516 | response = requests.get(f"https://api.polyhaven.com/categories/{asset_type}", headers=REQ_HEADERS) |
| 517 | if response.status_code == 200: |
| 518 | return {"categories": response.json()} |
| 519 | else: |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
MCP tool file registers a tool, performs a destructive sink (fs.unlink / shutil.rmtree / DROP TABLE / DELETE FROM / TRUNCATE / UPDATE ... SET / HTTP DELETE|PUT|PATCH / subprocess / exec / spawn), and emits no audit event anywhere in the file. Without an audit event, an investigator cannot answer "who deleted record X on day Y?" — the irreversible action leaves no trail. Closes the OWASP MCP Top 10:2025 MCP08 (Lack of Audit and Telemetry) gap. Distinct from MCP-201 (no confirmation) and MCP-283
Evidence
| 1 | # blender_mcp_server.py |
| 2 | from mcp.server.fastmcp import FastMCP, Context, Image |
| 3 | import socket |
| 4 | import json |
| 5 | import asyncio |
| 6 | import logging |
| 7 | import tempfile |
| 8 | from dataclasses import dataclass |
| 9 | from contextlib import asynccontextmanager |
| 10 | from typing import AsyncIterator, Dict, Any, List |
| 11 | import os |
| 12 | import sys |
| 13 | from pathlib import Path |
| 14 | import base64 |
| 15 | from urllib.parse import urlparse |
| 16 | |
| 17 | # Import telemetry |
| 18 | from .telemetry import record_startup, get_telemetry, EventType |
| 19 | from .telemetry_decorator import telemetry_t |
Remediation
Add a structured audit-event emit immediately after every destructive sink. Minimum schema: actor, action, target, outcome, request_id. Python: from acme.audit import audit_log @mcp.tool() def delete_record(token: str, record_id: str) -> dict: actor = verify_token(token) db.execute("DELETE FROM records WHERE id = %s", (record_id,)) audit_log( actor=actor.sub, action="delete_record", target=record_id, outcome=
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 686 | # Set color space based on map type |
| 687 | if map_type in ['color', 'diffuse', 'albedo']: |
| 688 | try: |
| 689 | image.colorspace_settings.name = 'sRGB' |
| 690 | except: |
| 691 | pass |
| 692 | else: |
| 693 | try: |
| 694 | |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 2769 | if auto_start and not bpy.types.blendermcp_server.running: |
| 2770 | bpy.types.blendermcp_server.start() |
| 2771 | try: |
| 2772 | bpy.context.scene.blendermcp_server_running = bpy.types.blendermcp_server.running |
| 2773 | except AttributeError: |
| 2774 | pass |
| 2775 | |
| 2776 | print("BlenderMCP addon registered") |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 248 | print(f"Error in client handler: {str(e)}") |
| 249 | finally: |
| 250 | try: |
| 251 | client.close() |
| 252 | except: |
| 253 | pass |
| 254 | print("Client handler stopped") |
| 255 | |
| 256 | def execute_command(self, command): |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 336 | try: |
| 337 | telemetry = get_telemetry() |
| 338 | if telemetry._check_user_consent(): |
| 339 | screenshot_url = telemetry.upload_screenshot(image_bytes, "screenshot") |
| 340 | except Exception: |
| 341 | pass # Silently fail - don't break screenshot for telemetry issues |
| 342 | |
| 343 | success = True |
| 344 | return Image(data=image_bytes, format="png") |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 699 | # Clean up temporary file |
| 700 | try: |
| 701 | os.unlink(tmp_path) |
| 702 | except: |
| 703 | pass |
| 704 | |
| 705 | if not downloaded_maps: |
| 706 | return {"error": f"No texture maps found for the requested resolution and format"} |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 365 | duration_ms=duration_ms, |
| 366 | error_message=error_msg, |
| 367 | metadata=metadata, |
| 368 | ) |
| 369 | except Exception: |
| 370 | pass |
| 371 | |
| 372 | |
| 373 | @mcp.tool() |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 691 | pass |
| 692 | else: |
| 693 | try: |
| 694 | image.colorspace_settings.name = 'Non-Color' |
| 695 | except: |
| 696 | pass |
| 697 | |
| 698 | downloaded_maps[map_type] = image |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 905 | pass |
| 906 | else: |
| 907 | try: |
| 908 | img.colorspace_settings.name = 'Non-Color' |
| 909 | except: |
| 910 | pass |
| 911 | |
| 912 | # Ensure the image is packed |
| 913 | if not img.packed_file: |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 233 | # Connection is dead, close it and create a new one |
| 234 | logger.warning(f"Existing connection is no longer valid: {str(e)}") |
| 235 | try: |
| 236 | _blender_connection.disconnect() |
| 237 | except: |
| 238 | pass |
| 239 | _blender_connection = None |
| 240 | |
| 241 | # Create a new connection if needed |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 747 | # Set color space based on map type |
| 748 | if map_type.lower() in ['color', 'diffuse', 'albedo']: |
| 749 | try: |
| 750 | tex_node.image.colorspace_settings.name = 'sRGB' |
| 751 | except: |
| 752 | pass # Use default if sRGB not available |
| 753 | else: |
| 754 | try: |
| 755 | tex_node.image.colorspace_settings.name = 'Non-Color' |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 231 | "status": "error", |
| 232 | "message": str(e) |
| 233 | } |
| 234 | client.sendall(json.dumps(error_response).encode('utf-8')) |
| 235 | except: |
| 236 | pass |
| 237 | return None |
| 238 | |
| 239 | # Schedule execution in main thread |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 900 | # Ensure proper color space |
| 901 | if map_type.lower() in ['color', 'diffuse', 'albedo']: |
| 902 | try: |
| 903 | img.colorspace_settings.name = 'sRGB' |
| 904 | except: |
| 905 | pass |
| 906 | else: |
| 907 | try: |
| 908 | img.colorspace_settings.name = 'Non-Color' |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 979 | pass # Use default if sRGB not available |
| 980 | else: |
| 981 | try: |
| 982 | tex_node.image.colorspace_settings.name = 'Non-Color' |
| 983 | except: |
| 984 | pass # Use default if Non-Color not available |
| 985 | |
| 986 | links.new(mapping.outputs['Vector'], tex_node.inputs['Vector']) |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 752 | pass # Use default if sRGB not available |
| 753 | else: |
| 754 | try: |
| 755 | tex_node.image.colorspace_settings.name = 'Non-Color' |
| 756 | except: |
| 757 | pass # Use default if Non-Color not available |
| 758 | |
| 759 | links.new(mapping.outputs['Vector'], tex_node.inputs['Vector']) |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 641 | # Clean up temporary file |
| 642 | try: |
| 643 | tempfile._cleanup() # This will clean up all temporary files |
| 644 | except: |
| 645 | pass |
| 646 | |
| 647 | return { |
| 648 | "success": True, |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 144 | # Close socket |
| 145 | if self.socket: |
| 146 | try: |
| 147 | self.socket.close() |
| 148 | except: |
| 149 | pass |
| 150 | self.socket = None |
| 151 | |
| 152 | # Wait for thread to finish |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 974 | # Set color space based on map type |
| 975 | if map_type.lower() in ['color', 'diffuse', 'albedo']: |
| 976 | try: |
| 977 | tex_node.image.colorspace_settings.name = 'sRGB' |
| 978 | except: |
| 979 | pass # Use default if sRGB not available |
| 980 | else: |
| 981 | try: |
| 982 | tex_node.image.colorspace_settings.name = 'Non-Color' |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 153 | if self.server_thread: |
| 154 | try: |
| 155 | if self.server_thread.is_alive(): |
| 156 | self.server_thread.join(timeout=1.0) |
| 157 | except: |
| 158 | pass |
| 159 | self.server_thread = None |
| 160 | |
| 161 | print("BlenderMCP server stopped") |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
get_viewport_screenshot
poll_hunyuan_job_status
get_hunyuan3d_status