[ ⌘K ]
← BACK TO SEARCH

GongRzhe/YOLO-MCP-Server

critical

No description

MCP server (purpose undetermined)

purpose: MCP server (purpose undetermined)threat: network exposed
Python34May 20, 2026May 20, 2026GITHUB
5/20/2026
high1 finding
server.py
1125@mcp.tool()
1126def comprehensive_image_analysis(
1127    image_path: str,
1128    confidence: float = 0.25,
1129    save_results: bool = False
1130) -> Dict[str, Any]:
1131    ...
1132    try:
1133        if not os.path.exists(image_path):
1134            return {"error": f"Image file not found: {image_path}"}
1135        
1136        # Load image
1137        image = load_image(image_path, is_path=True)
server.py:1125

// Exploitable if MCP is exposed to untrusted prompts (network_exposed) or by a compromised LLM (local_only).

The comprehensive_image_analysis tool accepts an arbitrary file path via the image_path parameter and reads the file using PIL's Image.open. There is no validation to restrict the path to a specific directory, allowing an attacker to read any file on the system that the server process has access to.

ImpactAn attacker could read sensitive files such as /etc/passwd, SSH keys, or application secrets by providing their paths as image_path.

FixRestrict image_path to a specific allowed directory (e.g., ./images) and validate that the resolved path stays within that directory. Use os.path.abspath and check against a whitelist.

high1 finding
server.py
174@mcp.tool()
175def detect_objects(
176    image_data: str,
177    model_name: str = "yolov8n.pt",
178    confidence: float = 0.25,
179    save_results: bool = False,
180    is_path: bool = False
181) -> Dict[str, Any]:
182    ...
183    try:
184        # Load image (supports path or base64)
185        image = load_image(image_data, is_path=is_path)
server.py:174

// Exploitable if MCP is exposed to untrusted prompts (network_exposed) or by a compromised LLM (local_only).

The detect_objects tool accepts an image_data parameter that can be a file path when is_path=True. The load_image function (line 79-102) opens the file using PIL.Image.open without any path validation, allowing arbitrary file reads.

ImpactAn attacker could read any file on the system by setting is_path=True and providing a path like /etc/passwd as image_data.

FixRestrict file paths to a specific allowed directory. Validate that the path is within an allowed scope before opening.

high1 finding
server.py
1262@mcp.tool()
1263def analyze_image_from_path(
1264    image_path: str,
1265    model_name: str = "yolov8n.pt",
1266    confidence: float = 0.25,
1267    save_results: bool = False
1268) -> Dict[str, Any]:
1269    ...
1270    try:
1271        # Call detect_objects function with is_path=True
1272        return detect_objects(
1273            image_data=image_path,
1274            model_name=model_name,
1275            confidence=confidence,
1276            save_results=save_results,
1277            is_path=True
1278        )
server.py:1262

// Exploitable if MCP is exposed to untrusted prompts (network_exposed) or by a compromised LLM (local_only).

The analyze_image_from_path tool directly passes the user-supplied image_path to detect_objects with is_path=True, which reads the file without any path validation.

ImpactSame as above: arbitrary file read.

FixRestrict image_path to an allowed directory.

high1 finding
server.py
522@mcp.tool()
523def validate_model(
524    model_path: str,
525    data_path: str,
526    imgsz: int = 640,
527    batch: int = 16
528) -> Dict[str, Any]:
529    ...
530    # Validate model path
531    if not os.path.exists(model_path):
532        return {"error": f"Model file not found: {model_path}"}
533    
534    # Validate dataset path
535    if not os.path.exists(data_path):
536        return {"error": f"Dataset not found: {data_path}"}
server.py:522server.py:574

// Exploitable if MCP is exposed to untrusted prompts (network_exposed) or by a compromised LLM (local_only).

Both validate_model and export_model accept model_path and data_path parameters and check their existence with os.path.exists. They also load the model file using get_model which reads the file. No path validation is performed.

ImpactAn attacker could read arbitrary .pt files or probe for existence of any file.

FixRestrict model_path and data_path to allowed directories.

high1 finding
server.py
459@mcp.tool()
460def train_model(
461    dataset_path: str,
462    model_name: str = "yolov8n.pt",
463    epochs: int = 100,
464    imgsz: int = 640,
465    batch: int = 16,
466    name: str = "yolo_custom_model",
467    project: str = "runs/train"
468) -> Dict[str, Any]:
469    ...
470    # Validate dataset path
471    if not os.path.exists(dataset_path):
472        return {"error": f"Dataset not found: {dataset_path}"}
server.py:459

// Exploitable if MCP is exposed to untrusted prompts (network_exposed) or by a compromised LLM (local_only).

The train_model tool accepts a dataset_path parameter and checks if it exists using os.path.exists. While it does not read the file content directly, the existence check can be used for information disclosure (path existence oracle). Additionally, the path is later passed to model.train which may read files from that path.

ImpactAn attacker could probe for existence of arbitrary files on the system, and potentially read files if the training process accesses them.

FixRestrict dataset_path to a specific allowed directory.

medium1 finding
server.py
929@mcp.tool()
930def start_camera_detection(
931    model_name: str = "yolov8n.pt",
932    confidence: float = 0.25,
933    camera_id: int = 0
934) -> Dict[str, Any]:
935    ...
936    # Start detection thread
937    camera_running = True
938    camera_last_access_time = time.time()
939    camera_thread = threading.Thread(
940        target=camera_detection_thread,
941        args=(model_name, confidence, 30, camera_id),
942        daemon=True
943    )
944    camera_thread.start()
server.py:929

// Exploitable if MCP is exposed to untrusted prompts (network_exposed) or by a compromised LLM (local_only).

The MCP server provides tools to start, stop, and read camera detections. This allows an attacker to activate the camera without any user interaction or consent, which is a privacy violation.

ImpactAn attacker could spy on the user by activating the camera and reading frames via get_camera_detections.

FixRequire explicit user confirmation before starting the camera, or remove camera functionality from the MCP server.

medium1 finding
server.py
110def get_model(model_name: str = "yolov8n.pt") -> YOLO:
111    """Get or load YOLO model from any of the configured model directories"""
112    if model_name in models:
113        return models[model_name]
114    
115    # Try to find the model in any of the configured directories
116    model_path = None
117    for directory in CONFIG["model_dirs"]:
118        potential_path = os.path.join(directory, model_name)
119        if os.path.exists(potential_path):
120            model_path = potential_path
121            break
server.py:110

// Exploitable if MCP is exposed to untrusted prompts (network_exposed) or by a compromised LLM (local_only).

The model_name parameter is used to construct a file path via os.path.join without any sanitization. An attacker could use path traversal characters (e.g., '../') to load arbitrary .pt files from outside the configured directories.

ImpactAn attacker could load arbitrary .pt files from the filesystem, potentially leading to arbitrary code execution if the model file contains malicious data (e.g., pickle deserialization).

FixValidate model_name against a whitelist of allowed model names, or ensure it does not contain path traversal sequences.

medium1 finding
server.py
386@mcp.tool()
387def track_objects(
388    image_data: str,
389    model_name: str = "yolov8n.pt",
390    confidence: float = 0.25,
391    tracker: str = "bytetrack.yaml",
392    save_results: bool = False
393) -> Dict[str, Any]:
394    ...
395    # Load model and perform tracking
396    model = get_model(model_name)
397    with redirect_stdout_to_stderr():
398        results = model.track(image, conf=confidence, tracker=tracker, save=save_results)
server.py:386

// Exploitable if MCP is exposed to untrusted prompts (network_exposed) or by a compromised LLM (local_only).

The tracker parameter is passed directly to model.track without validation. An attacker could provide a path to an arbitrary YAML file, potentially leading to file read or other issues.

ImpactAn attacker could read arbitrary YAML files from the filesystem by providing their path as the tracker parameter.

FixRestrict tracker to a whitelist of allowed tracker names (e.g., 'bytetrack.yaml', 'botsort.yaml').

medium1 finding
server.py
459@mcp.tool()
460def train_model(
461    dataset_path: str,
462    model_name: str = "yolov8n.pt",
463    epochs: int = 100,
464    imgsz: int = 640,
465    batch: int = 16,
466    name: str = "yolo_custom_model",
467    project: str = "runs/train"
468) -> Dict[str, Any]:
469    ...
470    with redirect_stdout_to_stderr():
471        results = model.train(
472            data=dataset_path,
473            epochs=epochs,
474            imgsz=imgsz,
475            batch=batch,
476            name=name,
477            project=project
478        )
server.py:459

// Exploitable if MCP is exposed to untrusted prompts (network_exposed) or by a compromised LLM (local_only).

The project and name parameters are used to construct file paths for saving training results. An attacker could use path traversal to write files to arbitrary locations.

ImpactAn attacker could write files to arbitrary directories on the filesystem, potentially overwriting important files or planting malicious content.

FixRestrict project and name to safe values, or ensure they do not contain path traversal sequences.

filesystem.writeenv.exposure
100
LLM-based
high findings+125
medium findings+60