Repository: BeehiveInnovations/zen-mcp-server
File: utils/security_config.py (Python)

Code before:
    Security:
        Fixes path traversal vulnerability (CWE-22) reported in:
        - https://github.com/BeehiveInnovations/zen-mcp-server/issues/293
        - https://github.com/BeehiveInnovations/zen-mcp-server/issues/312
    """
    try:
        resolved = path.resolve()
        resolved_str = str(resolved)

        # Check 1: Root directory (filesystem root)
        if resolved.parent == resolved:
            return True

        # Check 2: Exact match or subdirectory of dangerous paths
        for dangerous in DANGEROUS_PATHS:
            # Skip root "/" - already handled above
            if dangerous == "/":
                continue

            # Exact match
            if resolved_str == dangerous:
                return True

            # Subdirectory check: path starts with dangerous + separator
            # Use os.sep for platform-appropriate separator
            if resolved_str.startswith(dangerous + "/") or resolved_str.startswith(dangerous + "\\"):
                return True

        return False

    except Exception:
        return True  # If we can't resolve, consider it dangerous


Review comment (bug):
Thank you for your PR. I've reviewed your fix to is_dangerous_path. 

However, I found a major flaw in the subdirectory check logic in a Windows environment: the way the path separator is handled creates a double backslash (C:\\ format), which causes dangerous subdirectories (e.g., $\text{C:\Users}$) to be incorrectly evaluated as safe. Further revision is required to correctly block subdirectories.

print(is_dangerous_path(Path("C:\\"))) -> false

Code after:
    1. System paths (DANGEROUS_SYSTEM_PATHS): Block the path AND all subdirectories.
       Example: /etc is dangerous, so /etc/passwd is also blocked.

    2. Home containers (DANGEROUS_HOME_CONTAINERS): Block ONLY the exact path.
       Example: /home is blocked, but /home/user/project is allowed.
       Subdirectory access control is delegated to is_home_directory_root().

    Args:
        path: Path to check

    Returns:
        True if the path is dangerous and should not be accessed

    Security:
        Fixes path traversal vulnerability (CWE-22) while preserving
        user access to home subdirectories.
    """
    try:
        resolved = path.resolve()

        def _dangerous_variants(p: Path) -> set[Path]:
            variants = {p}
            # Only resolve paths that are absolute on the current platform.
            # This avoids turning Windows-style strings into nonsense absolute paths on POSIX.
            if p.is_absolute():
                try:
                    variants.add(p.resolve())
                except Exception:
                    pass
            return variants

        # Check 1: Root directory (filesystem root)
        if resolved.parent == resolved:
            return True

        # Check 2: System paths - block exact match AND all subdirectories
        for dangerous in DANGEROUS_SYSTEM_PATHS:
            # Skip root "/" - already handled above
            if dangerous == "/":
                continue

            for dangerous_path in _dangerous_variants(Path(dangerous)):
                # is_relative_to() correctly handles both exact matches and subdirectories.
                # Resolving the dangerous base path also handles platform symlinks
                # (e.g., macOS /etc -> /private/etc, /var -> /private/var).
                if resolved == dangerous_path or resolved.is_relative_to(dangerous_path):
                    return True

        # Check 3: Home containers - block ONLY exact match
        # Subdirectories like /home/user/project should pass through here
        # and be handled by is_home_directory_root() in resolve_and_validate_path()