all2md.mcp.security

Security utilities for MCP server path validation.

This module provides MCP-specific path validation and allowlist enforcement for secure file access in the MCP server.

Functions

  • validate_read_path: Validate a path is in the read allowlist

  • validate_write_path: Validate a path is in the write allowlist

  • prepare_allowlist_dirs: Convert allowlist strings to resolved Paths

  • secure_open_for_write: Open a file for writing with TOCTOU protection

exception all2md.mcp.security.MCPSecurityError

Bases: All2MdError

Raised when MCP security validation fails.

Initialize MCP security error.

Parameters:
  • message (str) – Error message

  • path (str | None) – Path that failed validation

__init__(message: str, path: str | None = None) None

Initialize MCP security error.

Parameters:
  • message (str) – Error message

  • path (str | None) – Path that failed validation

all2md.mcp.security.validate_read_path(path: str | Path, read_allowlist_dirs: list[str | Path] | None) Path

Validate a path is allowed for reading.

Parameters:
  • path (str | Path) – Path to validate

  • read_allowlist_dirs (list[str | Path] | None) – List of allowed read directory paths (strings or resolved Path objects), or None to allow all

Returns:

Validated, resolved path

Return type:

Path

Raises:

MCPSecurityError – If path is not in read allowlist or validation fails

Notes

The allowlist comparison uses resolved canonical paths, which are case-normalized on Windows. This prevents bypass via case variations on case-insensitive filesystems.

all2md.mcp.security.validate_write_path(path: str | Path, write_allowlist_dirs: list[str | Path] | None) Path

Validate a path is allowed for writing.

Uses security checks consistent with validate_local_file_access to ensure proper path validation and symlink resolution in all cases.

Parameters:
  • path (str | Path) – Path to validate

  • write_allowlist_dirs (list[str | Path] | None) – List of allowed write directory paths (strings or resolved Path objects), or None to allow all

Returns:

Validated, resolved path

Return type:

Path

Raises:

MCPSecurityError – If path is not in write allowlist or validation fails

Notes

The allowlist comparison uses resolved canonical paths, which are case-normalized on Windows. This prevents bypass via case variations on case-insensitive filesystems.

all2md.mcp.security.resolve_workspace_path(raw: str | Path, allowlist_dirs: list[str | Path] | None, *, must_exist: bool) Path | None

Resolve a possibly-relative path against the workspace (allowlist) dirs.

The first allowlist directory acts as the working directory, so agents can refer to files by a bare name or workspace-relative path instead of always supplying an absolute path.

Parameters:
  • raw (str | Path) – Path supplied by the caller. May be absolute, workspace-relative, or a bare filename.

  • allowlist_dirs (list[str | Path] | None) – Allowed directories (strings or resolved Paths). Used as candidate bases for relative paths, in order.

  • must_exist (bool) – When True (reads), each candidate is probed and the first that exists is returned, or None if none exist. When False (writes), the path is simply anchored to the first allowlist directory (or CWD) without probing.

Returns:

The resolved path, or None when must_exist is True and no candidate exists. Absolute inputs are returned unchanged.

Return type:

Path | None

all2md.mcp.security.prepare_allowlist_dirs(paths: list[str | Path] | None) list[Path] | None

Validate allowlist directory paths.

Ensures all paths exist and are directories. Resolves paths to canonical form, which normalizes case on Windows and follows symlinks.

Parameters:

paths (list[str | Path] | None) – List of directory paths (as strings or Path objects), or None for no restrictions

Returns:

Validated list of resolved Path objects, or None

Return type:

list[Path] | None

Raises:

MCPSecurityError – If any path is invalid or doesn’t exist

Notes

Paths are resolved to canonical form using Path.resolve(strict=True), which normalizes case on Windows filesystems. This ensures that case variations cannot bypass security checks on case-insensitive systems.

all2md.mcp.security.secure_open_for_write(validated_path: Path) BinaryIO

Open a file for writing with TOCTOU race condition protection.

This function opens a file using OS-level flags to prevent Time-Of-Check Time-Of-Use (TOCTOU) attacks where a file could be replaced with a symlink between validation and write operations.

Parameters:

validated_path (Path) – Path that has already been validated by validate_write_path(). Must be an absolute, resolved path.

Returns:

Binary file object opened for writing in a secure manner. Caller is responsible for closing this file.

Return type:

BinaryIO

Raises:

MCPSecurityError – If the file cannot be opened securely (e.g., it’s a symlink or access is denied)

Notes

Security measures: - On Unix-like systems: Uses O_NOFOLLOW flag to prevent following symlinks - On Windows: Uses os.open without follow_symlinks behavior - Creates new files with O_CREAT | O_EXCL when possible - For existing files, verifies they are not symlinks before opening

This function should be called immediately after validate_write_path() to minimize the TOCTOU window. The returned file object must be used for all write operations to ensure the validated path is actually being written to.