Use with caution. Address findings before production.
Scanned 5/3/2026, 7:38:21 PMยทCached resultยทFast Scanยท88 rulesยทHow we decide โ
AIVSS Score
Medium
Severity Breakdown
0
critical
6
high
56
medium
13
low
MCP Server Information
Findings
This package receives a C grade with a safety score of 72/100 and poses moderate security concerns, primarily driven by 6 high-severity issues and 56 medium-severity findings. The main risks stem from verbose error handling (43 findings), readiness problems (13 findings), and behavioral mismatches (8 findings) that could expose sensitive information or cause unexpected behavior. While no critical vulnerabilities were detected, the combination of these issues warrants careful review before installation, particularly if this server will handle sensitive data or run in production environments.
No known CVEs found for this package or its dependencies.
Scan Details
Want deeper analysis?
Fast scan found 75 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 75 findings
75 findings
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Timeline item property, keyframe, and clip-level tools.""" |
| 2 | |
| 3 | from src.granular.common import * # noqa: F401,F403 |
| 4 | |
| 5 | resolve = ResolveProxy() |
| 6 | |
| 7 | @mcp.resource("resolve://timeline-item/{timeline_item_id}") |
| 8 | def get_timeline_item_properties(timeline_item_id: str) -> Dict[str, Any]: |
| 9 | """Get properties of a specific timeline item by ID. |
| 10 | |
| 11 | Args: |
| 12 | timeline_item_id: The ID of the timeline item to get properties for |
| 13 | """ |
| 14 | pm, current_project = get_current_project() |
| 15 | if not current |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Project, render, cache, cloud, and project-property tools.""" |
| 2 | |
| 3 | from src.granular.common import * # noqa: F401,F403 |
| 4 | |
| 5 | resolve = ResolveProxy() |
| 6 | |
| 7 | @mcp.resource("resolve://projects") |
| 8 | def list_projects() -> List[str]: |
| 9 | """List all available projects in the current database.""" |
| 10 | project_manager = get_project_manager() |
| 11 | if not project_manager: |
| 12 | return ["Error: Failed to get Project Manager"] |
| 13 | |
| 14 | projects = project_manager.GetProjectListInCurrentFolder() |
| 15 | |
| 16 | # Filter out any |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Media pool operations and MediaPool API tools.""" |
| 2 | |
| 3 | from src.granular.common import * # noqa: F401,F403 |
| 4 | |
| 5 | resolve = ResolveProxy() |
| 6 | |
| 7 | @mcp.resource("resolve://media-pool-clips") |
| 8 | def list_media_pool_clips() -> List[Dict[str, Any]]: |
| 9 | """List all clips in the root folder of the media pool.""" |
| 10 | pm, current_project = get_current_project() |
| 11 | if not current_project: |
| 12 | return [{"error": "No project currently open"}] |
| 13 | |
| 14 | media_pool = current_project.GetMediaPool() |
| 15 | if not media_pool |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Resolve control resources, inspection helpers, and app-level tools.""" |
| 2 | |
| 3 | from src.granular.common import * # noqa: F401,F403 |
| 4 | |
| 5 | resolve = ResolveProxy() |
| 6 | |
| 7 | @mcp.resource("resolve://version") |
| 8 | def get_resolve_version() -> str: |
| 9 | """Get DaVinci Resolve version information.""" |
| 10 | resolve = get_resolve() |
| 11 | if resolve is None: |
| 12 | return "Error: Not connected to DaVinci Resolve" |
| 13 | return f"{resolve.GetProductName()} {resolve.GetVersionString()}" |
| 14 | |
| 15 | |
| 16 | @mcp.resource("resolve://current-page") |
| 17 | def |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """MediaPoolItem operations and metadata helpers.""" |
| 2 | |
| 3 | from src.granular.common import * # noqa: F401,F403 |
| 4 | |
| 5 | resolve = ResolveProxy() |
| 6 | |
| 7 | @mcp.tool() |
| 8 | def link_proxy_media(clip_name: str, proxy_file_path: str) -> str: |
| 9 | """Link a proxy media file to a clip. |
| 10 | |
| 11 | Args: |
| 12 | clip_name: Name of the clip to link proxy to |
| 13 | proxy_file_path: Path to the proxy media file |
| 14 | """ |
| 15 | pm, current_project = get_current_project() |
| 16 | if not current_project: |
| 17 | return "Error: No project curre |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
MCP tool with a destructive-sounding name is registered without the `destructiveHint: true` annotation. Clients rely on this hint to gate user confirmation, so the model may invoke the tool silently. Add `{ annotations: { destructiveHint: true } }` (TS) or `destructive_hint=True` on the tool decorator (Python).
Evidence
| 1 | """Gallery, still album, and powergrade tools.""" |
| 2 | |
| 3 | from src.granular.common import * # noqa: F401,F403 |
| 4 | |
| 5 | resolve = ResolveProxy() |
| 6 | |
| 7 | @mcp.tool() |
| 8 | def get_gallery_album_name() -> Dict[str, Any]: |
| 9 | """Get the name of the current gallery album.""" |
| 10 | resolve = get_resolve() |
| 11 | if resolve is None: |
| 12 | return {"error": "Not connected to DaVinci Resolve"} |
| 13 | project = resolve.GetProjectManager().GetCurrentProject() |
| 14 | if not project: |
| 15 | return {"error": "No project open"} |
| 16 | gallery = pro |
Remediation
Missing annotation: add `{ annotations: { destructiveHint: true } }` as the 4th argument to `server.tool(...)` (TS) or pass `destructive_hint=True` to the `@mcp.tool(...)` decorator (Python). readOnly-lying: remove the `readOnlyHint: true` / `read_only_hint=True` assertion, or refactor the handler so it no longer calls the destructive sink. Do not suppress with a waiver โ clients rely on these hints for user-facing confirmation.
LLM consensus
User-controlled value printed to terminal without ANSI escape sanitization. Malicious input can inject cursor-control sequences, rewrite earlier output, or hide shell commands from the operator.
Evidence
| 190 | if __name__ == "__main__": |
| 191 | if len(sys.argv) < 2: |
| 192 | print(f"Usage: {sys.argv[0]} <timecode> [color] [note]") |
| 193 | print(f"Example: {sys.argv[0]} 01:00:15:00 Red \"My marker note\"") |
| 194 | sys.exit(1) |
| 195 | |
| 196 | main() |
Remediation
Strip C0/C1 control codes before printing user-controlled values. Python: re.sub(r"[\x00-\x08\x0b-\x1f\x7f]", "", s). Prefer a structured logger (json/logfmt) over raw print to stdout.
User-controlled value printed to terminal without ANSI escape sanitization. Malicious input can inject cursor-control sequences, rewrite earlier output, or hide shell commands from the operator.
Evidence
| 189 | if __name__ == "__main__": |
| 190 | if len(sys.argv) < 2: |
| 191 | print(f"Usage: {sys.argv[0]} <timecode> [color] [note]") |
| 192 | print(f"Example: {sys.argv[0]} 01:00:15:00 Red \"My marker note\"") |
| 193 | sys.exit(1) |
Remediation
Strip C0/C1 control codes before printing user-controlled values. Python: re.sub(r"[\x00-\x08\x0b-\x1f\x7f]", "", s). Prefer a structured logger (json/logfmt) over raw print to stdout.
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
| 1079 | return f"Failed to delete keyframe for {property_name} at frame {frame}" |
| 1080 | |
| 1081 | except Exception as e: |
| 1082 | return f"Error deleting keyframe: {str(e)}" |
| 1083 | |
| 1084 | |
| 1085 | @mcp.tool() |
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
| 420 | except Exception as e: |
| 421 | logger.error(f"Error getting color settings: {str(e)}") |
| 422 | return {"error": f"Error getting color settings: {str(e)}"} |
| 423 | |
| 424 | def set_color_science_mode(project_obj, mode: str) -> bool: |
| 425 | """ |
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
| 564 | else: |
| 565 | return f"Failed to set some stabilization properties for timeline item '{timeline_item.GetName()}'" |
| 566 | except Exception as e: |
| 567 | return f"Error setting timeline item stabilization properties: {str(e)}" |
| 568 | |
| 569 | |
| 570 | @mcp.tool() |
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
| 189 | return clips |
| 190 | except Exception as e: |
| 191 | return [{"error": f"Error listing timeline clips: {str(e)}"}] |
| 192 | |
| 193 | |
| 194 | @mcp.tool() |
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
| 38 | # Get all settings |
| 39 | return current_project.GetSetting('') |
| 40 | except Exception as e: |
| 41 | return {"error": f"Failed to get project settings: {str(e)}"} |
| 42 | |
| 43 | |
| 44 | @mcp.resource("resolve://project-setting/{setting_name}") |
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
| 98 | else: |
| 99 | return f"Failed to start audio transcription for folder '{folder_name}'" |
| 100 | except Exception as e: |
| 101 | return f"Error during audio transcription: {str(e)}" |
| 102 | |
| 103 | |
| 104 | @mcp.tool() |
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
| 1182 | return f"Failed to set interpolation for {property_name} keyframe at frame {frame}" |
| 1183 | |
| 1184 | except Exception as e: |
| 1185 | return f"Error setting keyframe interpolation: {str(e)}" |
| 1186 | |
| 1187 | |
| 1188 | @mcp.tool() |
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
| 472 | else: |
| 473 | return f"Failed to set {path_type} cache path to '{path}'" |
| 474 | except Exception as e: |
| 475 | return f"Error setting cache path: {str(e)}" |
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
| 670 | else: |
| 671 | return f"Failed to set some audio properties for timeline item '{timeline_item.GetName()}'" |
| 672 | except Exception as e: |
| 673 | return f"Error setting timeline item audio properties: {str(e)}" |
| 674 | |
| 675 | |
| 676 | @mcp.resource("resolve://timeline-item/{timeline_item_id}/keyframes/{property_name}") |
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
| 1001 | return f"Failed to update keyframe value for {property_name} at frame {frame}" |
| 1002 | |
| 1003 | except Exception as e: |
| 1004 | return f"Error modifying keyframe: {str(e)}" |
| 1005 | |
| 1006 | |
| 1007 | @mcp.tool() |
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
| 44 | try: |
| 45 | os.makedirs(export_dir) |
| 46 | except Exception as e: |
| 47 | return f"Error creating directory for export: {str(e)}" |
| 48 | |
| 49 | # Export the folder |
| 50 | 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
| 160 | else: |
| 161 | return f"Failed to start audio transcription for clip '{clip_name}'" |
| 162 | except Exception as e: |
| 163 | return f"Error during audio transcription: {str(e)}" |
| 164 | |
| 165 | |
| 166 | @mcp.tool() |
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
| 91 | except Exception as e: |
| 92 | logger.error(f"Error getting project properties: {str(e)}") |
| 93 | return {"error": f"Error getting project properties: {str(e)}"} |
| 94 | |
| 95 | def get_project_property(project_obj, property_name: str) -> Any: |
| 96 | """ |
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
| 43 | else: |
| 44 | return f"Failed to link proxy media to clip '{clip_name}'" |
| 45 | except Exception as e: |
| 46 | return f"Error linking proxy media: {str(e)}" |
| 47 | |
| 48 | |
| 49 | @mcp.tool() |
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
| 244 | except Exception as e: |
| 245 | logger.error(f"Error getting timeline format settings: {str(e)}") |
| 246 | return {"error": f"Error getting timeline format settings: {str(e)}"} |
| 247 | |
| 248 | def set_timeline_format(project_obj, width: int, height: int, frame_rate: float, |
| 249 | interlaced: bool = False) -> bool: |
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
| 596 | except Exception as e: |
| 597 | logger.error(f"Error getting project info: {str(e)}") |
| 598 | return {"error": f"Error getting project info: {str(e)}"} |
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
| 395 | else: |
| 396 | return f"Failed to set some composite properties for timeline item '{timeline_item.GetName()}'" |
| 397 | except Exception as e: |
| 398 | return f"Error setting timeline item composite properties: {str(e)}" |
| 399 | |
| 400 | |
| 401 | @mcp.tool() |
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
| 438 | else: |
| 439 | return f"Failed to set proxy quality to '{quality}'" |
| 440 | except Exception as e: |
| 441 | return f"Error setting proxy quality: {str(e)}" |
| 442 | |
| 443 | |
| 444 | @mcp.tool() |
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 | except Exception as e: |
| 551 | logger.error(f"Error getting project metadata: {str(e)}") |
| 552 | return {"error": f"Error getting project metadata: {str(e)}"} |
| 553 | |
| 554 | def get_project_info(project_obj) -> Dict[str, Any]: |
| 555 | """ |
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
| 895 | return f"Failed to add keyframe for {property_name} at frame {frame}" |
| 896 | |
| 897 | except Exception as e: |
| 898 | return f"Error adding keyframe: {str(e)}" |
| 899 | |
| 900 | |
| 901 | @mcp.tool() |
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 | else: |
| 474 | return f"Failed to set some retime properties for timeline item '{timeline_item.GetName()}'" |
| 475 | except Exception as e: |
| 476 | return f"Error setting timeline item retime properties: {str(e)}" |
| 477 | |
| 478 | |
| 479 | @mcp.tool() |
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
| 197 | else: |
| 198 | return f"Failed to clear audio transcription for clip '{clip_name}'" |
| 199 | except Exception as e: |
| 200 | return f"Error clearing audio transcription: {str(e)}" |
| 201 | |
| 202 | |
| 203 | @mcp.tool() |
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
| 129 | return properties |
| 130 | |
| 131 | except Exception as e: |
| 132 | return {"error": f"Error getting timeline item properties: {str(e)}"} |
| 133 | |
| 134 | |
| 135 | @mcp.resource("resolve://timeline-items") |
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
| 104 | else: |
| 105 | return f"Failed to set project setting '{setting_name}'" |
| 106 | except Exception as e: |
| 107 | return f"Error setting project setting: {str(e)}" |
| 108 | |
| 109 | |
| 110 | @mcp.tool() |
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
| 335 | except Exception as e: |
| 336 | logger.error(f"Error getting SuperScale settings: {str(e)}") |
| 337 | return {"error": f"Error getting SuperScale settings: {str(e)}"} |
| 338 | |
| 339 | def set_superscale_settings(project_obj, enabled: bool, quality: int = 0) -> bool: |
| 340 | """ |
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
| 54 | else: |
| 55 | return f"Failed to export folder '{folder_name}'" |
| 56 | except Exception as e: |
| 57 | return f"Error exporting folder: {str(e)}" |
| 58 | |
| 59 | |
| 60 | @mcp.tool() |
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
| 141 | else: |
| 142 | return f"Failed to clear audio transcription for folder '{folder_name}'" |
| 143 | except Exception as e: |
| 144 | return f"Error clearing audio transcription: {str(e)}" |
| 145 | |
| 146 | |
| 147 | @mcp.tool() |
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
| 248 | else: |
| 249 | return f"Failed to set {property_name} for timeline item '{timeline_item.GetName()}'" |
| 250 | except Exception as e: |
| 251 | return f"Error setting timeline item property: {str(e)}" |
| 252 | |
| 253 | |
| 254 | @mcp.tool() |
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
| 246 | except Exception as e: |
| 247 | logger.error(f"Error saving project: {str(e)}") |
| 248 | return f"Error saving project: {str(e)}" |
| 249 | |
| 250 | |
| 251 | @mcp.tool() |
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
| 302 | return settings |
| 303 | except Exception as e: |
| 304 | return {"error": f"Failed to get cache settings: {str(e)}"} |
| 305 | |
| 306 | |
| 307 | @mcp.tool() |
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
| 404 | else: |
| 405 | return f"Failed to set proxy mode to '{mode}'" |
| 406 | except Exception as e: |
| 407 | return f"Error setting proxy mode: {str(e)}" |
| 408 | |
| 409 | |
| 410 | @mcp.tool() |
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
| 272 | return f"Failed to close project '{project_name}'" |
| 273 | except Exception as e: |
| 274 | logger.error(f"Error closing project: {str(e)}") |
| 275 | return f"Error closing project: {str(e)}" |
| 276 | |
| 277 | |
| 278 | @mcp.resource("resolve://cache/settings") |
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
| 803 | } |
| 804 | |
| 805 | except Exception as e: |
| 806 | return {"error": f"Error getting timeline item keyframes: {str(e)}"} |
| 807 | |
| 808 | |
| 809 | @mcp.tool() |
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 | else: |
| 371 | return f"Failed to set optimized media mode to '{mode}'" |
| 372 | except Exception as e: |
| 373 | return f"Error setting optimized media mode: {str(e)}" |
| 374 | |
| 375 | |
| 376 | @mcp.tool() |
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
| 336 | else: |
| 337 | return f"Failed to set cache mode to '{mode}'" |
| 338 | except Exception as e: |
| 339 | return f"Error setting cache mode: {str(e)}" |
| 340 | |
| 341 | |
| 342 | @mcp.tool() |
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
| 122 | else: |
| 123 | return f"Failed to replace clip '{clip_name}'" |
| 124 | except Exception as e: |
| 125 | return f"Error replacing clip: {str(e)}" |
| 126 | |
| 127 | |
| 128 | @mcp.tool() |
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
| 185 | return items |
| 186 | except Exception as e: |
| 187 | return [{"error": f"Error listing timeline items: {str(e)}"}] |
| 188 | |
| 189 | |
| 190 | @mcp.tool() |
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
| 1244 | return f"Failed to enable {keyframe_mode} keyframe mode for timeline item '{timeline_item.GetName()}'" |
| 1245 | |
| 1246 | except Exception as e: |
| 1247 | return f"Error enabling keyframe mode: {str(e)}" |
| 1248 | |
| 1249 | |
| 1250 | @mcp.tool() |
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
| 133 | return value |
| 134 | except Exception as e: |
| 135 | logger.error(f"Error getting project property {property_name}: {str(e)}") |
| 136 | return {"error": f"Error getting project property: {str(e)}"} |
| 137 | |
| 138 | def set_project_property(project_obj, property_name: str, property_value: Any) -> bool: |
| 139 | """ |
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
| 194 | # Inspect the object we've retrieved |
| 195 | return inspect_object(obj) |
| 196 | except Exception as e: |
| 197 | return {"error": f"Error inspecting object: {str(e)}"} |
| 198 | |
| 199 | |
| 200 | @mcp.resource("resolve://layout-presets") |
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
| 510 | except subprocess.TimeoutExpired: |
| 511 | return False, "Connection timed out" |
| 512 | except Exception as e: |
| 513 | return False, str(e) |
| 514 | |
| 515 | # โโโ Interactive UI โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ |
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
| 308 | else: |
| 309 | return f"Failed to set crop {crop_type.lower()} for timeline item '{timeline_item.GetName()}'" |
| 310 | except Exception as e: |
| 311 | return f"Error setting timeline item crop: {str(e)}" |
| 312 | |
| 313 | |
| 314 | @mcp.tool() |
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
| 80 | else: |
| 81 | return f"Failed to unlink proxy media from clip '{clip_name}'" |
| 82 | except Exception as e: |
| 83 | return f"Error unlinking proxy media: {str(e)}" |
| 84 | |
| 85 | |
| 86 | @mcp.tool() |
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
| 90 | if force: |
| 91 | subprocess.run(['pkill', '-9', 'resolve']) |
| 92 | else: |
| 93 | subprocess.run(['pkill', 'resolve']) |
| 94 | return True |
| 95 | |
| 96 | # If all methods fail, return False |
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
| 81 | if force: |
| 82 | subprocess.run(['taskkill', '/F', '/IM', 'Resolve.exe']) |
| 83 | else: |
| 84 | subprocess.run(['taskkill', '/IM', 'Resolve.exe']) |
| 85 | return True |
| 86 | |
| 87 | elif sys_platform == 'linux': |
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
| 72 | '-e', 'tell application "DaVinci Resolve" to quit with saving' |
| 73 | ] |
| 74 | |
| 75 | subprocess.run(cmd) |
| 76 | return True |
| 77 | |
| 78 | elif sys_platform == 'windows': |
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
| 88 | # Linux - use pkill |
| 89 | logger.info("Using pkill to quit Resolve on Linux") |
| 90 | if force: |
| 91 | subprocess.run(['pkill', '-9', 'resolve']) |
| 92 | else: |
| 93 | subprocess.run(['pkill', 'resolve']) |
| 94 | return True |
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
| 79 | # Windows - use taskkill |
| 80 | logger.info("Using taskkill to quit Resolve on Windows") |
| 81 | if force: |
| 82 | subprocess.run(['taskkill', '/F', '/IM', 'Resolve.exe']) |
| 83 | else: |
| 84 | subprocess.run(['taskkill', '/IM', 'Resolve.exe']) |
| 85 | return True |
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 AND contains a destructive sink (fs.unlink, os.remove, shutil.rmtree, DROP/DELETE FROM/TRUNCATE/ UPDATE ... SET, HTTP DELETE/PUT/PATCH, subprocess.run, exec/spawn), but the file has no confirmation path โ no `elicit()` call, no `dry_run`/`dryRun` flag, no `idempotency_key`/`idempotencyKey`, no `confirmation`/`confirm` token. A destructive handler that fires on the first call with no reversibility signal is an autonomous-action hazard (MCP Top-10 R10). Add one of:
Evidence
| 1 | """Project, render, cache, cloud, and project-property tools.""" |
| 2 | |
| 3 | from src.granular.common import * # noqa: F401,F403 |
| 4 | |
| 5 | resolve = ResolveProxy() |
| 6 | |
| 7 | @mcp.resource("resolve://projects") |
| 8 | def list_projects() -> List[str]: |
| 9 | """List all available projects in the current database.""" |
| 10 | project_manager = get_project_manager() |
| 11 | if not project_manager: |
| 12 | return ["Error: Failed to get Project Manager"] |
| 13 | |
| 14 | projects = project_manager.GetProjectListInCurrentFolder() |
| 15 | |
| 16 | # Filter out any |
Remediation
Pick one confirmation mechanism and add it to the destructive handler: - make the client confirm via `elicit()` before touching the sink, - accept a `dry_run` / `dryRun` boolean input and branch off the sink when true (return what would change), - require an `idempotency_key` / `idempotencyKey` the caller provides on the first call and echoes back to commit, - require a `confirmation` / `confirm` token as an input field. If the destructive call is genuinely irrelevant to the tool
MCP tool file registers a tool AND contains a destructive sink (fs.unlink, os.remove, shutil.rmtree, DROP/DELETE FROM/TRUNCATE/ UPDATE ... SET, HTTP DELETE/PUT/PATCH, subprocess.run, exec/spawn), but the file has no confirmation path โ no `elicit()` call, no `dry_run`/`dryRun` flag, no `idempotency_key`/`idempotencyKey`, no `confirmation`/`confirm` token. A destructive handler that fires on the first call with no reversibility signal is an autonomous-action hazard (MCP Top-10 R10). Add one of:
Evidence
| 1 | #!/usr/bin/env python3 |
| 2 | """ |
| 3 | DaVinci Resolve MCP Server (Compound Tools) |
| 4 | |
| 5 | 27 compound tools covering 100% of the DaVinci Resolve Scripting API (336 methods). |
| 6 | Each tool groups related operations via an 'action' parameter. |
| 7 | |
| 8 | Usage: |
| 9 | python src/server.py # Start the MCP server |
| 10 | python src/server.py --full # Start the 328-tool granular server instead |
| 11 | """ |
| 12 | |
| 13 | VERSION = "2.3.3" |
| 14 | |
| 15 | import base64 |
| 16 | import os |
| 17 | import sys |
| 18 | import json |
| 19 | import logging |
| 20 | import platform |
| 21 | import subprocess |
| 22 | import te |
Remediation
Pick one confirmation mechanism and add it to the destructive handler: - make the client confirm via `elicit()` before touching the sink, - accept a `dry_run` / `dryRun` boolean input and branch off the sink when true (return what would change), - require an `idempotency_key` / `idempotencyKey` the caller provides on the first call and echoes back to commit, - require a `confirmation` / `confirm` token as an input field. If the destructive call is genuinely irrelevant to the tool
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | #!/usr/bin/env python3 |
| 2 | """ |
| 3 | DaVinci Resolve MCP Server โ Universal Installer |
| 4 | |
| 5 | Supports: macOS, Windows, Linux |
| 6 | Configures: Claude Desktop, Claude Code, Cursor, VS Code (Copilot), |
| 7 | Windsurf, Cline, Roo Code, Zed, Continue, and manual setup. |
| 8 | |
| 9 | Usage: |
| 10 | python install.py # Interactive mode |
| 11 | python install.py --clients all # Install all clients non-interactively |
| 12 | python install.py --clients cursor,claude-desktop --no-venv |
| 13 | python install.py --help |
| 14 | """ |
| 15 | |
| 16 | import a |
Remediation
Declare a real authentication mechanism in the manifest, matching what the running server actually enforces: - `"auth": "bearer"` with a token scheme documented for callers - `"auth": "oauth"` / `"oauth2": { ... }` for delegated flows - `"apiKey": { "header": "X-API-Key", "prefix": "..." }` - `"mtls": true` when client certificates are required If the server is intentionally unauthenticated (stdio-only, local developer tool, trusted-host network), document the assumption in the manifest via a `"
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | # DaVinci Resolve MCP Server |
| 2 | |
| 3 | [](https://github.com/samuelgursky/davinci-resolve-mcp/releases) |
| 4 | [](#api-coverage) |
| 5 | [-blue.svg)](#server-modes) |
| 6 | [](#test-results) |
| 7 | [, document the assumption in the manifest via a `"
Time-of-check-to-time-of-use race. Code calls `os.path.exists` / `fs.existsSync` to check a path, then `open` / `readFileSync` / `unlink` on the same name within a few lines โ without a lock or atomic-open. An attacker who can race the filesystem (symlink, file replacement) between the check and the use gets the action applied to a different target. Replace the check-then-use pattern with the action's own error handling: try the open and catch FileNotFoundError / ENOENT. For atomic creation use
Evidence
| 1 | #!/usr/bin/env python3 |
| 2 | """ |
| 3 | DaVinci Resolve MCP Server - Layout Presets Utilities |
| 4 | |
| 5 | This module provides functions for working with DaVinci Resolve UI layout presets: |
| 6 | - Saving layout presets |
| 7 | - Loading layout presets |
| 8 | - Exporting/importing preset files |
| 9 | - Managing layout configurations |
| 10 | """ |
| 11 | |
| 12 | import os |
| 13 | import json |
| 14 | import logging |
| 15 | from typing import Dict, List, Any, Optional, Union |
| 16 | |
| 17 | # Configure logging |
| 18 | logger = logging.getLogger("davinci-resolve-mcp.layout_presets") |
| 19 | |
| 20 | |
| 21 | def _validate_path_within_directory( |
Remediation
Replace check-then-use with action-then-handle: Python: `try: with open(p) as f: ... except FileNotFoundError: ...` Node: `try { fs.readFileSync(p); } catch (e) { if (e.code === "ENOENT") ... }` For atomic file creation: Python: `os.open(p, os.O_RDWR | os.O_CREAT | os.O_EXCL)` Node: `fs.open(p, "wx")` โ fails if file exists, no race. When you genuinely must check first, use `flock` (Python `fcntl`) or a similar per-process advisory lock to make the window uninteresting to a
Time-of-check-to-time-of-use race. Code calls `os.path.exists` / `fs.existsSync` to check a path, then `open` / `readFileSync` / `unlink` on the same name within a few lines โ without a lock or atomic-open. An attacker who can race the filesystem (symlink, file replacement) between the check and the use gets the action applied to a different target. Replace the check-then-use pattern with the action's own error handling: try the open and catch FileNotFoundError / ENOENT. For atomic creation use
Evidence
| 1 | """Project, render, cache, cloud, and project-property tools.""" |
| 2 | |
| 3 | from src.granular.common import * # noqa: F401,F403 |
| 4 | |
| 5 | resolve = ResolveProxy() |
| 6 | |
| 7 | @mcp.resource("resolve://projects") |
| 8 | def list_projects() -> List[str]: |
| 9 | """List all available projects in the current database.""" |
| 10 | project_manager = get_project_manager() |
| 11 | if not project_manager: |
| 12 | return ["Error: Failed to get Project Manager"] |
| 13 | |
| 14 | projects = project_manager.GetProjectListInCurrentFolder() |
| 15 | |
| 16 | # Filter out any |
Remediation
Replace check-then-use with action-then-handle: Python: `try: with open(p) as f: ... except FileNotFoundError: ...` Node: `try { fs.readFileSync(p); } catch (e) { if (e.code === "ENOENT") ... }` For atomic file creation: Python: `os.open(p, os.O_RDWR | os.O_CREAT | os.O_EXCL)` Node: `fs.open(p, "wx")` โ fails if file exists, no race. When you genuinely must check first, use `flock` (Python `fcntl`) or a similar per-process advisory lock to make the window uninteresting to a
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
| 122 | pass |
| 123 | elif property_type == "float" and not isinstance(value, float): |
| 124 | try: |
| 125 | value = float(value) |
| 126 | except (ValueError, TypeError): |
| 127 | pass |
| 128 | elif property_type == "bool" and not isinstance(value, bool): |
| 129 | # Convert string representations of boolean |
| 130 | if isinstance(value, str): |
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
| 2572 | # Remove the directory if empty |
| 2573 | try: |
| 2574 | if os.path.isdir(folder_path) and not os.listdir(folder_path): |
| 2575 | os.rmdir(folder_path) |
| 2576 | except OSError: |
| 2577 | pass |
| 2578 | return {"files": file_details, "format": used_format, "folder": folder_path, "cleaned_up": cleanup} |
| 2579 | elif action == "delete_stills": |
| 2580 | stills = album.GetStills() or [] |
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
| 2781 | finally: |
| 2782 | if undo_started: |
| 2783 | try: |
| 2784 | comp.EndUndo(keep_undo) |
| 2785 | except Exception: |
| 2786 | pass |
| 2787 | if error_message is not None: |
| 2788 | results.append({"index": index, "error": error_message}) |
| 2789 | elif keep_undo: |
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
| 2557 | except UnicodeDecodeError: |
| 2558 | entry["data_base64"] = base64.b64encode(raw).decode("ascii") |
| 2559 | else: |
| 2560 | entry["data_base64"] = base64.b64encode(raw).decode("ascii") |
| 2561 | except OSError: |
| 2562 | pass |
| 2563 | file_details.append(entry) |
| 2564 | # Cleanup: remove exported files now that data is inlined (default: True) |
| 2565 | cleanup = p.get("cleanup", 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
| 229 | # Try to clean up temp file |
| 230 | try: |
| 231 | if os.path.exists(temp_file): |
| 232 | os.remove(temp_file) |
| 233 | except: |
| 234 | pass |
| 235 | success = True |
| 236 | except Exception as e: |
| 237 | logger.error(f"Error in export method: {str(e)}") |
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
| 117 | if property_type == "int" and not isinstance(value, int): |
| 118 | try: |
| 119 | value = int(value) |
| 120 | except (ValueError, TypeError): |
| 121 | pass |
| 122 | elif property_type == "float" and not isinstance(value, float): |
| 123 | try: |
| 124 | value = float(value) |
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
| 160 | if hasattr(lua_table, 'GetKeyList'): |
| 161 | try: |
| 162 | # Some DaVinci Resolve objects have a GetKeyList() method |
| 163 | return lua_table.GetKeyList() |
| 164 | except: |
| 165 | pass |
| 166 | |
| 167 | # Try different iteration methods that might work with Lua tables |
| 168 | try: |
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
| 169 | # Some Lua tables can be iterated directly |
| 170 | for key in lua_table: |
| 171 | keys.append(key) |
| 172 | return keys |
| 173 | except: |
| 174 | pass |
| 175 | |
| 176 | # Try manual iteration with pairs-like behavior (if available) |
| 177 | # This is a fallback for APIs that don't support Python-style iteration |
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
| 121 | if resolve_obj: |
| 122 | try: |
| 123 | state["version"] = resolve_obj.GetVersionString() |
| 124 | except: |
| 125 | pass |
| 126 | |
| 127 | try: |
| 128 | state["product_name"] = resolve_obj.GetProductName() |
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
| 126 | pass |
| 127 | |
| 128 | try: |
| 129 | state["product_name"] = resolve_obj.GetProductName() |
| 130 | except: |
| 131 | pass |
| 132 | |
| 133 | try: |
| 134 | state["current_page"] = resolve_obj.GetCurrentPage() |
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
| 289 | ) |
| 290 | base_prefix = result.stdout.strip() |
| 291 | if result.returncode == 0 and base_prefix: |
| 292 | return base_prefix |
| 293 | except Exception: |
| 294 | pass |
| 295 | |
| 296 | resolved = Path(python_path).resolve() |
| 297 | if resolved.parent.name.lower() in {"scripts", "bin"}: |
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
| 228 | # If we found items, return as list |
| 229 | if result: |
| 230 | return result |
| 231 | except: |
| 232 | pass |
| 233 | |
| 234 | # If conversion failed, return string representation |
| 235 | return str(lua_obj) |
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
| 2566 | if cleanup: |
| 2567 | for f in file_details: |
| 2568 | try: |
| 2569 | os.remove(f["path"]) |
| 2570 | except OSError: |
| 2571 | pass |
| 2572 | # Remove the directory if empty |
| 2573 | try: |
| 2574 | if os.path.isdir(folder_path) and not os.listdir(folder_path): |
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.
set_timeline_item_transform
set_project_setting
import_media
switch_page
link_proxy_media
get_gallery_album_name
resolve_control