Validate File Paths in MCP Servers: Preventing Directory Traversal Attacks

Validate File Paths in MCP Servers: Preventing Directory Traversal Attacks

AI agents that interact with filesystems through Model Context Protocol (MCP) servers face a critical security challenge: path validation. When an agent receives a request like ../secrets/config.json, your MCP server must decide whether to serve the file or reject it. Without proper validation, directory traversal attacks can expose sensitive data far beyond intended boundaries, turning a helpful assistant into an unintentional data breach vector.

Understanding the Directory Traversal Threat

Directory traversal attacks exploit insufficient path validation to access files outside the intended directory scope. Attackers craft paths containing sequences like ../ or absolute paths like /etc/passwd to escape the sandboxed environment and access system files, configuration data, or other sensitive resources.

The risk is amplified in MCP server contexts because AI agents process natural language requests that can be subtly manipulated. A user might ask "show me the parent directory's config file" or an attacker might embed malicious paths in seemingly innocent prompts. Without explicit validation, the MCP server may resolve these paths relative to its working directory and serve files that should remain inaccessible.

The consequences extend beyond data exposure. Compromised configuration files can reveal API keys, database credentials, or authentication tokens. In containerized environments, attackers might access mounted secrets or host filesystem paths that weren't properly isolated.

Implementing Path Validation Controls

Effective path validation requires multiple defensive layers working together. The first layer involves canonicalization—converting paths to their absolute, normalized form before any access checks. This eliminates ambiguity from relative path sequences and symbolic links that could bypass simple string-based filters.

import os
from pathlib import Path

def validate_path(requested_path: str, allowed_root: str) -> bool:
    """
    Validate that requested_path stays within allowed_root.
    Returns True if path is safe to access.
    """
    # Resolve both paths to absolute, canonical forms
    try:
        allowed_root = Path(allowed_root).resolve()
        requested = Path(requested_path)

        # Handle absolute vs relative path inputs
        if requested.is_absolute():
            full_path = requested.resolve()
        else:
            full_path = (allowed_root / requested).resolve()

        # Critical check: path must be within allowed_root
        return allowed_root in full_path.parents or full_path == allowed_root

    except (ValueError, OSError):
        # Path resolution failed - reject for safety
        return False

# Example usage
allowed_root = "/var/mcp/data"
safe_path = validate_path("../secrets/config.json", allowed_root)
# Returns False - escapes allowed_root

The second layer implements deny-list patterns through mechanisms like .mcpignore files. The MCPIgnore Filesystem MCP server demonstrates this approach, using pattern matching to prevent access to sensitive files regardless of path construction:

func shouldIgnore(fileName string) bool {
    // Check against .mcpignore patterns
    // Sensitive patterns: *.pem, *.key, .env, config.json
    // Also block path traversal attempts
    if strings.Contains(fileName, "..") {
        return true
    }
    // Pattern matching against .mcpignore rules
    return matchesIgnorePatterns(fileName)
}

Defense-in-Depth Architecture

Robust MCP servers combine path validation with additional security boundaries. Operating system-level sandboxing restricts the server process to specific directories through chroot jails or container filesystem isolation. This provides defense even if application-level validation contains bugs.

Authorization checks represent another critical layer. The MCP authorization specification supports OAuth 2.1 token verification, allowing servers to validate that requesting agents have appropriate permissions before file access:

from mcp.server.auth.provider import AccessToken, TokenVerifier
from mcp.server.auth.settings import AuthSettings

class SecureMCPServer:
    def __init__(self, auth_settings: AuthSettings):
        self.verifier = TokenVerifier(auth_settings)

    async def read_file(self, path: str, token: AccessToken):
        # Verify authorization first
        if not await self.verifier.verify(token, scope="files:read"):
            raise PermissionError("Insufficient scope for file access")

        # Then validate path
        if not self.validate_path(path):
            raise ValueError("Path traversal detected")

        # Finally, check ignore patterns
        if self.should_ignore(path):
            raise ValueError("Access to this file type is restricted")

        return await self._read_file(path)

Testing and Verification

Validation logic requires comprehensive testing against edge cases. Test suites should include:

  • Relative path sequences: ../../../etc/passwd, ..\..\windows\system32\config\sam
  • URL-encoded variants: %2e%2e%2f representing ../
  • Null byte injections: file.txt%00.jpg (historical bypass technique)
  • Unicode normalization attacks using homoglyph characters
  • Symbolic link traversal where links point outside allowed_root
  • Case sensitivity variations on Windows systems

Automated security testing should verify that all these inputs are properly rejected while legitimate paths within the allowed scope succeed.

Recommendations for MCP Server Operators

Operators deploying filesystem MCP servers should implement these practices:

  1. Define explicit allow-lists rather than relying on deny-lists—specify exactly which paths and file types are accessible
  2. Run servers with minimal privileges using dedicated service accounts without shell access
  3. Enable comprehensive audit logging for all file operations including rejected attempts
  4. Regularly review .mcpignore patterns as new sensitive file types emerge in your environment
  5. Test validation logic against known traversal payloads before production deployment
  6. Monitor for anomalous patterns such as repeated failed path access attempts

Proper path validation transforms MCP servers from potential security liabilities into trustworthy AI infrastructure components.

AgentGuard360

Built for agents and humans. Comprehensive threat scanning, device hardening, and runtime protection. All without data leaving your machine.

Coming Soon